2

テスト実行エンジン用の一時的なコンテナー/VM の (リモート) シェルで、本質的に任意のコマンドを実行する必要があります。場合によっては、これらがバックグラウンド プロセスをリークし、コマンド全体がハングすることがあります。これは、次の単純なコマンドに要約できます。

$ sh -c 'sleep 30 & echo payload'
payload
$

ここで、backgroundedsleep 30はリークされたプロセスの役割を果たし (実際には のようなものになりますdbus-daemon)、echo は実際に実行したいものです。ここsleep 30 & echo payloadでは、アトミックな不透明なコマンドの例と見なす必要があります。

上記のコマンドは問題なく、シェルとスリープの stdout/stderr が PTY であるため、すぐに戻ります。ただし、コマンドの出力をパイプ/ファイルにキャプチャすると (テスト ランナーは、結局のところ、すべてをログに保存する必要があります)、コマンド全体がハングします。

$ sh -c 'sleep 30 & echo payload' | cat
payload
# ... does not return to the shell (until the sleep finishes)

現在、これは、stdout/err の FD を から決定し、同じ stdout/stderr を持つすべてのプロセスを/proc/$$/fd/{1,2}反復して強制終了する、かなりばかげて複雑なシェル マジックで修正できます。ls /proc/[0-9]*/fd/*しかし、これには多くの壊れやすいシェル コードと高価なシェル文字列の比較が含まれます。

これらのリークされたバックグラウンド プロセスをよりエレガントでシンプルな方法でクリーンアップする方法はありますか? setsid助けにならない:

$ sh -c 'setsid -w sh -c "sleep 30 & echo payload"' | cat
payload
# hangs...

リークされたプロセス (dbus-daemon など) はしばしば自身を設定するため、プロセス グループ/セッションを強制終了するだけでは不十分であることに注意してください。

PS私は、これらの環境ではPOSIXシェルまたはbashしか想定できません。Python、Perl などはありません。

前もって感謝します!

4

3 に答える 3

0

うーん、これを読み直したので、あなたが求めている解決策を提供することはできません(systemdを使用してそれらを殺します)。私たちが思いついたのは、単にプロセスを無視することですが、待っていた単一のプロセスが完了したときに確実にハングしないようにすることです。これは、閉じられるパイプとは明らかに異なることに注意してください。

もう 1 つのオプションは、完全ではありませんが便利ですが、prctl(2) と PR_SET_CHILD_SUBREAPER を使用してローカル リーパーになることです。これにより、それ以外の場合は init に再親化されるすべてのプロセスの親になることができます。この配置では、あなたをppidとして持つすべてのプロセスを強制終了しようとすることができます. これはひどいことですが、cgroup の使用に最も近い方法です。

ただし、このヘルパーをルートとして実行していない限り、実際のテストでは、潜んでいて殺せない setuid が生成される可能性があることに注意してください。本当に悩ましい問題です。

于 2015-09-02T10:09:48.277 に答える