次のコマンドを実行すると:
dmesg | head -n 10
私はOSがdmesg
10行を読んだ後に何らかの信号を送り返すと仮定します。head
どのように動作しますか?head
カーネルに何を教えてください。
これは通常の「クリーン」停止なので、プログラムのシャットダウンとは異なります。
答え1
これは、オペレーティングシステムのバッファと10番目と11番目の書き込みのタイミングによって異なりますdmesg
。
head
10行を書き込んで終了してdmesg
受信します。SIGPIPE信号パイプに書き続ける場合。
オペレーティングシステムのバッファによっては、通常dmesg
10行以上が使用される前に書き込まれます。head
head
10行以上が使用されていることを確認するには、次のようにします。
strace -f sh -c 'dmesg | head -n 10'
head
(プロセスを見てread
システムコールの回数を計算します。)
書き込み速度に与える影響を確認してください。
strace -f sh -c "perl -le '$|++;print 1 while 1' | head -n 10"
答え2
次の場合、この
write()
機能は失敗します。…プロセスが読み取れるように開かないか、一方の端だけが開いているパイプまたはFIFOに書き込みを試みます。 SIGPIPE信号もスレッドに送信する必要があります。
したがって、イベントの順序は次のようになります。
プロセスが
head
終了します。これにより、標準入力(パイプの一端)を含む開いているすべてのファイル記述子が閉じます。プロセスはパイプのもう一方の端である標準出力を
dmesg
呼び出します。write()
これはSIGPIPEをプロセスに渡します
dmesg
。dmesg
SIGPIPE には特別な処理がないため、プロセスを終了する基本操作が適用されます。
SIGPIPE信号の動作を変更して実験できます。たとえば、パイプは1行を印刷して終了します。
$ yes | head -1
y
$
ただし、SIGPIPE を無視しても終了しません。
$ trap '' PIPE
$ yes | head -1
y
この時点で、yes
プロセスはまだパイプへの書き込みを試みていますが、EPIPE によって書き込みが失敗します。
答え3
head
閉鎖標準入力10行を印刷した後。その後、検出dmesg
されました。標準出力閉じて終了します。
より正確には、呼び出しはエラーをdmesg
受け取ります。EPIPE
write
標準出力。
~からdmesg.cソースコードはここにあります:https://github.com/karelzak/util-linux/blob/v2.27.1/sys-utils/dmesg.c#L654-L659
rc = fwrite(p, 1, len, out) != len;
if (rc != 0) {
if (errno != EPIPE)
err(EXIT_FAILURE, _("write failed"));
exit(EXIT_SUCCESS);
}