web-dev-qa-db-ja.com

posix close呼び出しが失敗した場合はどうすればよいですか?

私のシステム(Ubuntu Linux、glibc)では、close呼び出しのマニュアルページに、返される可能性のあるいくつかのエラー戻り値が指定されています。それはまた言います

Close()の戻り値をチェックしないのはよくあることですが、それでも重大なプログラミングエラーです。

同時に

戻り値は診断にのみ使用してください。特に、EINTRの後でclose()を再試行しないでください。これにより、別のスレッドからの再利用された記述子が閉じられる可能性があります。

そのため、戻り値を無視したり、呼び出しを再試行したりすることはできません。

それを踏まえて、close()呼び出しの失敗をどのように処理しますか?

ファイルに何かを書き込んでいるときにエラーが発生した場合、データの損失を回避するために、おそらくどこか他の場所に情報を書き込もうとするはずです。

ファイルを読み取っていただけの場合、失敗をログに記録して、何も起こらないふりをしてプログラムを続行できますか?警告、ファイル記述子のリークなどはありますか?

18
Ilya Popov

実際には、エラー時にcloseを再試行しないでください。エラーが発生したかどうかに関係なく、closeが返された後、closeに渡したfdは常に無効(クローズ)です。場合によっては、エラーにより、データが失われた(特定のNFSセットアップ)か、デバイスのハードウェアの異常な状態(たとえば、テープを巻き戻すことができなかった)が示されることがあります。そのため、データの損失を避けるために注意が必要な場合がありますが、 fdをもう一度閉じます。

理論的には、closeEINTRで失敗し、システムが同意しない場合、POSIXはfdが開いたままであるかどうかについて以前は不明でした。状態を把握することが重要であるため(そうしないと、fdリークまたはマルチスレッドプログラムで非常に危険な二重クローズのバグが発生します)、解決策として Austin Groupの問題#529 将来のバージョンの動作を厳密に指定しましたPOSIXの場合、EINTRはfdが開いたままであることを意味します。これは、他の場所でのEINTRの定義と一致する正しい動作ですが、Linuxはそれを受け入れません。 (FWIWこれには、libc syscallラッパーレベルで可能な簡単な回避策があります。 glibc PR#14627 を参照してください。)幸い、実際にはそれが発生することはありません。

参考になると思われるいくつかの関連質問:

まず、EINTRは正確に次のことを意味します:システムコールが中断されました。これがclose()コールで発生した場合、実行できることはまったくありません。

おそらく、fdがファイルに属している場合、このファイルが破損している可能性があるという事実を追跡することとは別に、close()のエラーについては、戻り値に応じて実行できることはほとんどありません。申し訳ありませんが、クローズを再試行できる唯一のケースはEBUSYですが、まだ確認していません。

そう:

  • close()の結果をチェックしないと、ファイルの破損、特に切り捨てを見逃す可能性があります。
  • エラーにもよりますが、ほとんどの場合何もできません。失敗したclose()は、アプリケーションの範囲外で何かがひどく間違っていることを意味します。
1
Eugen Rieck