web-dev-qa-db-ja.com

ライブラリでのEINTRの適切な処理方法

ライブラリのEINTRに関して推奨されるエチケットは何ですか?

現在、POSIX APIでいくつかのファイルシステムタスクを実行する関数を作成していますが、使用する多くの呼び出しでEINTRが返される可能性があります。さらに、関数は状況によってはブロックする可能性があります。 (興味のある人のために、それはロック機構を実装しています。)

これをできるだけ一般的にするために、中断されたシステムコールを処理する適切な方法を知りたいのですが。

  • 私が読んだほとんどのソースから、人々は通常、電話を再試行し、ビジネスを続けます。ただし、かなり時間がかかる場合があるため、機能を中断する正当な理由がある可能性があるため、ここでそれを行うのが正しいかどうかはわかりません。さらに、これはEINTRが関数によって飲み込まれるだけであり、呼び出し元がそれが発生したことを示すすべての情報を失うことを意味します。

  • 私の現在の戦略は、EINTRを受け取ったらすぐに操作を中止し、それについて呼び出し元に通知することです。このようにして、呼び出し元は私の機能を再試行するかどうかを決定できますよね? (または、おそらく私の信号の理解に欠陥がありますか?)

9
Rufflewind

NIXのシグナル

他のプロセスがプロセスシグナルを送信すると、プログラムは実行中の処理を停止します...

1)記述したハンドラーコードを実行します。シグナルが到着したときに、プログラムが何をしているのかわかりません。それは信号の考え方であり、完全に非同期にすることができます。

2)シグナルハンドラーが完了すると、通常は戻り値が返され、プログラムは中断したところから何も起こらなかったかのように続行します。

Richard Stevensに役立つ情報が見つかりました

以前のUNIXシステムの特徴は、「低速」システムコールでプロセスがブロックされているときにプロセスがシグナルをキャッチした場合、システムコールが中断されたことです。システムコールがエラーを返し、errnoがEINTRに設定されました。これは、シグナルが発生してプロセスがそれをキャッチしたため、ブロックされたシステムコールをウェイクアップする必要がある何かが発生した可能性が高いという想定の下で行われました。

中断された読み取りと書き込みのPOSIX.1セマンティクスは、2001バージョンの規格で変更されました。以前のバージョンでは、部分的な量のデータを処理した読み取りと書き込みの処理方法を実装に選択できました。読み取りがデータを受信して​​アプリケーションのバッファーに転送したが、アプリケーションが要求したすべてのデータをまだ受信しておらず、その後中断された場合、オペレーティングシステムはerrnoをEINTRに設定してシステムコールに失敗するか、システムコールを成功させて戻ります。受信したデータの部分的な量。同様に、アプリケーションのバッファーにデータの一部を転送した後に書き込みが中断された場合、オペレーティングシステムはerrnoをEINTRに設定してシステムコールに失敗するか、システムコールを成功させて、書き込まれたデータの一部を返します。従来、System Vから派生した実装はシステムコールに失敗しましたが、BSDから派生した実装は部分的に成功します。 2001バージョンのPOSIX.1標準では、BSDスタイルのセマンティクスが必要です。

システムコールが中断された場合の問題は、エラーの戻りを明示的に処理する必要があることです。典型的なコードシーケンス(読み取り操作を想定し、中断された場合でも読み取りを再開したいと想定)は次のようになります。

again:
    if ((n = read(fd, buf, BUFFSIZE)) < 0) {
        if (errno == EINTR)
            goto again;     /* just an interrupted system call */
        /* handle other errors */
    }

アプリケーションが中断されたシステムコールを処理する必要がないように、4.2BSDは、特定の中断されたシステムコールの自動再起動を導入しました。

4