`dmesg | head`で(どのように)10行の出力後にdmesgが終了しますか? [コピー]

`dmesg | head`で(どのように)10行の出力後にdmesgが終了しますか? [コピー]

次のコマンドを実行すると:

dmesg | head -n 10

私はOSがdmesg10行を読んだ後に何らかの信号を送り返すと仮定します。headどのように動作しますか?headカーネルに何を教えてください。

これは通常の「クリーン」停止なので、プログラムのシャットダウンとは異なります。

答え1

これは、オペレーティングシステムのバッファと10番目と11番目の書き込みのタイミングによって異なりますdmesg

head10行を書き込んで終了してdmesg受信します。SIGPIPE信号パイプに書き続ける場合。

オペレーティングシステムのバッファによっては、通常dmesg10行以上が使用される前に書き込まれます。head

head10行以上が使用されていることを確認するには、次のようにします。

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()関数のPOSIX仕様:

次の場合、このwrite()機能は失敗します。

…プロセスが読み取れるように開かないか、一方の端だけが開いているパイプまたはFIFOに書き込みを試みます。 SIGPIPE信号もスレッドに送信する必要があります。

したがって、イベントの順序は次のようになります。

  1. プロセスがhead終了します。これにより、標準入力(パイプの一端)を含む開いているすべてのファイル記述子が閉じます。

  2. プロセスはパイプのもう一方の端である標準出力をdmesg呼び出します。write()

  3. これはSIGPIPEをプロセスに渡しますdmesg

  4. dmesgSIGPIPE には特別な処理がないため、プロセスを終了する基本操作が適用されます。

SIGPIPE信号の動作を変更して実験できます。たとえば、パイプは1行を印刷して終了します。

$ yes | head -1
y
$

ただし、SIGPIPE を無視しても終了しません。

$ trap '' PIPE
$ yes | head -1
y

この時点で、yesプロセスはまだパイプへの書き込みを試みていますが、EPIPE によって書き込みが失敗します。

答え3

head閉鎖標準入力10行を印刷した後。その後、検出dmesgされました。標準出力閉じて終了します。

より正確には、呼び出しはエラーをdmesg受け取ります。EPIPEwrite標準出力

~から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);
}

関連情報