2011-07-15 12 views
1

マニュアルページを読んで閉じると、シグナルによって中断された場合、fdの状態は不定です。このケースを処理するためのベストプラクティスがあるか、またはその後OSの問題になると想定されています。クローズが中断された場合、または失敗した場合、fdの状態はどうなりますか?

EIOがfdを適切にクローズした後にエラーが発生したと想定します。

+0

結果を特定できない場合、実際には他の人の問題になっていなければなりません。 OSがディスクリプタをリサイクルした場合に備えて、ソケットを再び閉じることができませんでした。 – jsimmons

+0

実際、manページには、どちらの場合もfdの状態が不定になってしまうというメッセージがあります。 – jsimmons

答えて

1

、あなたのプログラムは、長い時間のために実行したい場合は、可能なファイルディスクリプタのリークが唯一のオペレーティングシステムの問題になることはありません。もちろん、多くのファイルディスクリプタを使用しない短命のプログラムでは、ディスクリプタを閉じずに終了するオプションがあり、プログラムの終了時にディスクリプタを閉じるカーネルに依存します。だから、私の答えの残りの部分については、あなたのプログラムは長時間走っていると仮定します。

あなたのプログラムがマルチスレッド化されていない場合、あなたは非常に簡単な状況があります。一方

int close_some_fd(int fd, int *was_interrupted) { 
    *was_interrupted = 0; 
    /* this is point X to which I will draw your attention later. */ 
    for (;;) { 
    if (0 == close(fd)) 
     return 0; /* Success. */ 
    if (EIO != errno) 
     return -1; /* Some failure, not interrupted by a signal. */ 

    /* Our close attempt was interrupted. */ 
    *was_interrupted = 1; 
    int fdflags = 0; 
    /* Just use the fd to find out if it is still open. */ 
    if (0 != fcntl(fd, F_GETFD, &fdflags)) 
     return 0; /* Interrupted, but file is also closed. So we are done. */ 
    } 
} 

を、あなたのコードがマルチスレッド化されている場合、いくつかの他のスレッド(そしておそらくあなたはドン1」そのようなネームサービスキャッシュとしてトン制御は、)dupdup2socketopenacceptまたはカーネルがファイルディスクリプタを割り当てますいくつかの他の同様の機能を呼ばれている可能性があります。

あなたがで開始ファイルディスクリプタと、新たに別のスレッドによって開かれたファイル記述子の違いを見分けることができるようにする必要がありますこのような環境で同様のアプローチを動作させるために。まだ開いていないfdの番号が小さいことが分かっているのであれば、それを割り引くには十分ですが、マルチスレッド環境ではこれがまだ当てはまるかどうかを簡単に判断する方法はありません。

1つのオプションは、あなたのプログラムがで動作するすべてのファイル記述子にいくつかの一般的な側面に依存することです。例えば、それはO_CLOEXECを使用したことがないならば、あなたはポイントでO_CLOEXECフラグがコードにXをマークし、その後、あなたはこのようなfcntlに既存のコールを変更するfcntlを使用することができます。

if (0 = fcntl(fd, F_GETFD, &fdflags)) { 
     if (fdflags & O_CLOEXEC) { 
     /* open, and still marked with O_CLOEXEC, unused elsewhere. */ 
     continue; 
     } else { 
     return 0; /* Interrupted, but file is also closed. So we are done. */ 
     } 
    } 

あなたはこれを調整することができます(st_devst_inoを記録、例えばおそらくfstatO_CLOEXEC以外のものを使用するためのアプローチが、あなたはあなたのマルチスレッドプログラムの残りの部分が何をしているかを確認することができない場合は、この一般的な考え方は不満足である可能性が高いです。

があるにも少し問題がある別のアプローチだが、これを提供することがあります。これは、ファイルディスクリプタを閉じるのではなく、sendmsgを使用してUnixドメインソケットを介してファイルディスクリプタを、ファイルディスクリプタを閉じるジョブだけを持つ別のシングルスレッドの専用サーバーに渡すことです。はい、これはちょっと嫌です。あるものの、このアプローチのいくつかの面白い性質は:

  1. あなたのFDが実際にサーバに渡され、正常に閉じられたかどうかの不確実性を避けるために、あなたはおそらく今後FD-閉じ-OKメッセージのリターンチャンネルからお読みくださいサーバーから戻します。これにより、sendmsgの実行中にシグナル配信をブロックする必要がなくなります。しかし、これは、すべてのファイル記述子を閉じるためのユーザースペースのコンテキストスイッチオーバーヘッドを意味します(コストを償却するためにそれらを一括しない限り)。スレッドAがスレッドBからの要求に対応するfd-closed-OKレポートを読み取っている状況を避ける必要があります。パフォーマンスを制限するクローズ操作を直列化するか、応答を逆多重化することで問題を回避できます。複合体)。あるいは、他のIPCメカニズムを使用して、シリアライズまたはデマルチプレックス(SYSVセマフォなど)を避けることもできます。
  2. 大量のプロセスでは、カーネルのファイルディスクリプタガベージコレクタ装置に面倒な負荷がかかりますが、通常はそれほど負荷がかかりませんので、いくつかの面白い現象があります。

は、私が最も頻繁に動作するアプリケーションで、個人的にやるだろう何のためとして、私はファイルディスクリプタの種類は私がクローズされたかについての仮定を作ることができるどの程度まで把握したいです。たとえば、それらが通常ソケットである場合、私はテストプログラムでこれを試して、EIOが通常ファイル記述子を閉じたままにしておくかどうかを判断します。すなわち、実際には、EIOのファイルディスクリプタの理論上の未指定の状態が予測可能かどうかを判断します。 fdが何か(例えば、ディスクファイル、ソケット、tty、...)であれば、これはうまく動作しません。もちろん、オープンソースのオペレーティングシステムを使用している場合は、カーネルのソースを読み込んで、可能な結果が何であるかを判断することができます。

確かに、fdクローズ・サーバをシャドーしてfdクローズにスケールアウトすることを心配する前に、上記の実験ベースのシステムを試してみたいと思います。

関連する問題