read()
とのwrite()
呼び出しのマニュアルページを読むと、これらの呼び出しは、ブロックする必要があるかどうかに関係なく、シグナルによって中断されるようです。
特に、仮定
- プロセスが何らかのシグナルのハンドラーを確立します。
- デバイスが設定されて
O_NONBLOCK
いない状態で開かれている(つまり、ブロッキングモードで動作している) - その後、プロセス
read()
はデバイスから読み取るシステムコールを行い、その結果、カーネル空間でカーネル制御パスを実行します。 read()
プロセスがカーネル空間で実行している間、ハンドラーが以前にインストールされたシグナルがそのプロセスに配信され、そのシグナルハンドラーが呼び出されます。
SUSv3の「System Interfaces volume(XSH)」のマニュアルページと適切なセクションを読むと、次のことがわかります。
私。a read()
がデータを読み込む前に信号によって中断された場合(つまり、データが利用できなかったためブロックしなければならなかった場合)、errno
[EINTR]に設定された-1を返します。
ii。a read()
がデータを正常に読み取った後(つまり、要求の処理をすぐに開始できた)にシグナルによって中断された場合、読み取られたバイト数を返します。
質問A):
どちらの場合(ブロック/ブロックなし)でも、信号の配信と処理は完全に透過的ではないと仮定するのは正しいread()
ですか?
ケースi。ブロッキングread()
は通常、プロセスをTASK_INTERRUPTIBLE
状態にするため、シグナルが配信されるとカーネルがプロセスをTASK_RUNNING
状態にするため、理解できるようです。
しかし、read()
ブロックする必要がなく(ケースii。)、カーネル空間でリクエストを処理している場合、シグナルの到着とその処理は、ハードウェアの到着と適切な処理と同様に透過的であると考えていました。割り込みになります。特に、シグナルの配信時に、プロセスは一時的にユーザーモードになり、そのシグナルハンドラーを実行して、最終的に戻り、中断されたread()
(カーネルスペースで)処理を終了しread()
て、完了までの経過後、プロセスはread()
(ユーザー空間での)呼び出しの直後のポイントに戻り、結果として利用可能なすべてのバイトが読み込まれます。
しかし、ii。はread()
、データがすぐに利用可能であるため、が中断されていることを暗示しているように見えますが、(すべてではなく)一部のデータのみを返します。
これにより、2番目の(そして最後の)質問に導かれます。
質問B):
A)での私の仮定が正しい場合、read()
要求を満たすために利用可能なデータがあるためブロックする必要はないのに、なぜ中断されるのですか?言い換えると、なぜread()
シグナルハンドラーを実行した後に再開されず、最終的にすべての利用可能なデータ(結局利用可能だった)が返されることになりますか?