プロセスの子孫


20

プロセスコンテナを構築しようとしています。コンテナは他のプログラムをトリガーします。たとえば、「&」を使用して実行中のバックグラウンドタスクを起動するbashスクリプト。

私が望んでいる重要な機能はこれです:私がコンテナを殺すとき、その下にスポーンされたすべてのものが殺されるべきです。直接子供だけでなく、その子孫も。

このプロジェクトを始めたとき、プロセスを強制終了すると、その子も自動的に強制終了されると誤って信じていました。私は同じ間違った考えを持っていた人々からのアドバイスを求めてきました。信号をキャッチして子供に殺害を伝えることは可能ですが、ここでは探していません。

xtermを閉じると、その中で実行されていたものはすべて、nohup'dされない限り殺されるので、私は達成したいものを信じています。これには、孤立したプロセスが含まれます。それが私が再現したいものです。

私が探しているのは、Unixセッションに関するものだと思います。

プロセスのすべての子孫を識別する信頼できる方法があれば、それらにも任意のシグナルを送信できると便利です。例:SIGUSR1。


さて、親プロセスを強制終了SIGHUPすると、直接子プロセスに送信されます。ハングアップシグナルのデフォルトハンドラーはプロセスの実行を中止するため、デフォルトルートはすべての子孫を殺すことです。プロセスおよびプロセスグループの詳細をご覧ください。
アレックス

xtermを閉じると、TTYが破棄されるため、xtermで生成されたすべてが強制終了されます。子プロセスが使用できるttyを作成する方法を考え出すことができれば、TTYを破棄して同じことを達成できます。そのTTYを閉じなかったプロセス(nohup&friends)は、SIGHUPを取得します。
パトリック

回答:


23

プロセスにシグナルを送信すると、そのプロセスは強制終了されます。プロセスを殺すと他のプロセスも殺すという噂がどのように始まったのだろうか、それは特に直感に反しているようだ。

ただし、複数のプロセスを強制終了する方法があります。ただし、1つのプロセスにシグナルを送信することはありません。1234がプロセスグループリーダーのPIDであるPGID(プロセスグループID)であるシグナルを-1234に送信することにより、プロセスグループ全体を強制終了できます。パイプラインを実行すると、パイプライン全体がプロセスグループとして開始されます(アプリケーションは、setpgidまたはを呼び出すことでこれを変更できますsetpgrp)。

バックグラウンド(foo &)でプロセスを開始すると、それらは独自のプロセスグループに属します。プロセスグループは、端末へのアクセスを管理するために使用されます。通常、フォアグラウンドプロセスグループのみが端末にアクセスできます。バックグラウンドジョブは同じセッションに残りますが、セッション全体を強制終了したり、セッション内のプロセスグループやプロセスを列挙したりする機能はないため、あまり役に立ちません。

端末を閉じると、カーネルは、端末を制御端末SIGHUPとして持つすべてのプロセスに信号を送信します。これらのプロセスはセッションを形成しますが、すべてのセッションに制御端末があるわけではありません。したがって、プロジェクトの場合、スクリプトスクリーンなどによって作成された独自のターミナルですべてのプロセスを開始する可能性が1つあります。setsid

プロセスを他の何もしない独自のユーザーとして実行することで、より分離できます。次に、すべてのプロセスを強制終了します。そのユーザーとしてkillシステムコールまたはユーティリティ)を実行し、PID引数として-1を使用して強制終了します。つまり、「そのユーザーのすべてのプロセス」を意味します。

さらに隔離することもできますが、実際のcontainerで含まれるプロセスを実行することにより、かなり多くのセットアップを行うことができます。


独自のプロセスをプログラムする場合は、次のようなものを使用できます。prctl(PR_SET_PDEATHSIG, SIGHUP);詳細:man7.org/linux/man-pages/man2/prctl.2.html
Alexis Wilke

ジル、あなたはこれに言及します-「端末を閉じると、カーネルはそれを制御端末として持つすべてのプロセスにシグナルSIGHUPを送信します」。このことから、ターミナルはセッションリーダー(シェル)にSIGHUPを送信し、セッションリーダーはそれをセッション内のすべてのプロセスグループに転送すると推測しています。どちらが正しいでしょうか?
iruvar

4

親スクリプト内で、killシグナルをトラップし、すべての子を殺します。例えば、

#!/bin/bash
# kill the parent and children together
trap "kill 0" EXIT
# create all the children
for n in $(seq 1 100)
do
    ( echo "begin $n"; sleep 60; echo "end $n" ) &
done
# wait for the children to complete
wait

2

プロセスのすべての子孫を識別する信頼できる方法pstree <pid>は、pidが親プロセスIDであるコマンドを使用することです。

pstree こちらのmanページをご覧ください

プロセスグループのすべてのメンバーに信号をkillpg(<pgrp>, <sig>);
送るには:pgrpはプロセスグループ番号で、sigは信号です。

指定したプロセスグループの子を待つには: waitpid(-<pgrp>, &status, ...);

あなたがやっていることの代替は、新しいbashシェルでプロセスコンテナを実行することです。コマンドbashを使用して新しいbashシェルを作成し、プロセスを実行します。すべてのプロセスを終了する場合は、コマンドでシェルを終了しますexit


killpgを使用すると、必要なことを実行できると思います。ありがとう。
クレイグターナー

1

つかいます

unshare -fp --kill-child -- yourprogram

killするとunshare、すべての子プロセス(yourprogram生成された可能性がある)が強制終了されます。

これは、util-linuxで可能になりました2.32このアップストリームを実装しました。ユーザーの名前空間(カーネル設定オプションCONFIG_USER_NS=y)またはルート権限のいずれかが必要です。こちらもご覧ください


0

rkillからのコマンドpslistパッケージには、信号(または特定の送信SIGTERM指定されたプロセスとそのすべての子孫にデフォルトで):

rkill [-SIG] pid/name...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.