私は読んでいます。アプエそしてシステムコール割り込みチャプターが私を混乱させます。
本をもとに私が理解した内容を書きたいのですが訂正してください。
初期のUNIXシステムの特徴は、「遅い」システムコールでプロセスがブロックされている間にシグナルが捕捉されると、システムコールが中断されることです。システムコールはエラーを返し、
errno
に設定されますEINTR
。ここでは、シグナルが発生してプロセスがそれをキャッチしたため、ブロックされたシステムコールを起動する必要がある可能性が高いと仮定します。だからそれが言うのはより早いUNIXシステムの特徴があります。私のプログラムがシステムコールを使用している場合、プログラムはいつでもシグナルをキャプチャすると中断/停止します。 (デフォルトハンドラはキャプチャと見なされますか?)
たとえば、10GBのデータを読み取るシステムコールがある場合、読み込み中にシグナル(たとえば)を
read
送信すると失敗して返されます。kill -SIGUSR1 pid
read
アプリケーションが中断されたシステムコールを処理しないようにするために、4.2BSDは中断された特定のシステムコールを自動的に再開する機能を導入しました。自動再起動のためのシステムコールは
ioctl
、、、、、およびです。前述のように、これらの機能の最初の5つは、低速デバイスからの信号によってのみ中断されます。信号がキャッチされると常に中断されます。これにより、中断時に操作を再開したくないアプリケーションに問題が発生する可能性があるため、4.3BSDではプロセスが信号でこの機能を無効にすることができます。read
readv
write
writev
wait
waitpid
wait
waitpid
だから前に自動再起動導入された後、中断されたシステムコールを直接処理する必要がありました。次のコードを書く必要があります。
システムコールを中断する際の問題は、エラーリターンを明示的に処理する必要があることです。一般的なコードシーケンス(読み取り操作を想定し、中断された場合でも読み取りを再開すると仮定)は次のとおりです。
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* just an interrupted system call */
/* handle other errors */
}
しかし、今ではこの種のコードを書く必要はありません。自動再起動器具。
それでは、私の理解がすべて正確であれば、今中断されたシステムコールについて何/なぜ気にする必要がありますか?システム/オペレーティングシステムが自動的に処理するようです。
答え1
シグナルハンドラによるシステムコールの中断は、さまざまなブロッキングシステムコールの場合にのみ発生し、プログラマが明示的に設定したシグナルハンドラによってシステムコールが中断された場合に発生します。
さらに、自動システムコールの再起動任意に選択できる特徴。SA_RESTART
シグナルハンドラを構築するときにフラグを付けて、システムコールを自動的に再開することを選択できます。 (例えば)Linuxに規定されているように信号(7)マニュアルページ:
If a signal handler is invoked while a system call or library
function call is blocked, then either:
* the call is automatically restarted after the signal handler
returns; or
* the call fails with the error EINTR.
Which of these two behaviors occurs depends on the interface and
whether or not the signal handler was established using the
SA_RESTART flag (see sigaction(2)).
上記の引用の最後の文が示すように、この機能を使用することを選択しても、すべてのシステム呼び出しに適用されるわけではなく、適用されるシステム呼び出しのセットはUNIX実装によって異なります。 Linuxsignal(7)
のマニュアルページでは、このフラグを使用すると自動的に再起動される複数のシステムコールを指摘していますSA_RESTART
が、次のようなハンドラを構築するときにこのフラグを指定しても再起動しないさまざまなシステムコールも指摘しています。
* "Input" socket interfaces, when a timeout (SO_RCVTIMEO) has been
set on the socket using setsockopt(2): accept(2), recv(2),
recvfrom(2), recvmmsg(2) (also with a non-NULL timeout argu‐
ment), and recvmsg(2).
* "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has
been set on the socket using setsockopt(2): connect(2), send(2),
sendto(2), and sendmsg(2).
* File descriptor multiplexing interfaces: epoll_wait(2),
epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).
* System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
semtimedop(2).
これらのシステムコールでは、APUEで説明されている形式のループを使用して手動で再起動することが重要です。例:
while ((ret = some_syscall(...)) == -1 && errno == EINTR)
continue;
if (ret == -1)
/* Handle error */ ;
答え2
[APUEの内容は読まなかったが、引用された内容はあまりないようです。]
私のプログラムがシステムコールを使用している場合、プログラムはいつでもシグナルをキャプチャすると中断/停止します。
システムコールではありません。ただ一部システムコールは中断される可能性があります。
(デフォルトハンドラはキャプチャと見なされますか?)
いいえ。
たとえば、読み取りsyscallがあり、10 GBのデータの読み取り中に読み取り中に2つの信号のうちの1つ(例:kill -SIGUSR1 pid)を送信すると、読み取りは失敗して返されます。
10 GB read() は、読み込み前に中断された場合にのみ EINTR を返します。1バイトラド;それ以外の場合は、読み取られたデータの量を返します(短い読み取り=成功、errnoは関係ありません)。
[接続されたチートでは説明されていません。]
それでは、私の理解がすべて正確であれば、今中断されたシステムコールについて何/なぜ気にする必要がありますか?システム/オペレーティングシステムが自動的に処理するようです。
なぜなら欲しいかもしれないからな何信号が受信されると、信号ハンドラで多くの操作を実行することはできません。 malloc()またはstdio(またはprintf())を使用するすべての操作は不可能です。したがって、プログラムのメインループで割り込みを処理する必要があります。そうするには、何らかの方法でブロックread()から割り込みを行う必要があります(read()は、poll()がfd読み取り準備を返した後でもブロックできます)。
[これ以前はリンクだけで説明されています]