web-dev-qa-db-ja.com

親が終了した後に子プロセスを停止させる方法は?

子プロセスを1つだけ生成するプロセスがあるとします。親プロセスが何らかの理由で(通常または異常に、kill、^ C、失敗などをアサートして)終了した場合、子プロセスを停止させます。それを正しく行う方法は?


Stackoverflowに関するいくつかの同様の質問:


Windowsのstackoverflowに関するいくつかの同様の質問:

199
Paweł Hajdan

子は、次のようにprctl() syscallでオプションPR_SET_PDEATHSIGを指定することにより、親が死んだときにSIGHUP(または他の信号)を配信するようカーネルに要求できます。

prctl(PR_SET_PDEATHSIG, SIGHUP);

詳細については、man 2 prctlを参照してください。

編集:これはLinux専用です

174
qrdl

私は同じ問題を解決しようとしていますが、私のプログラムはOS X上で実行する必要があるため、Linuxのみのソリューションはうまくいきませんでした。

私はこのページの他の人々と同じ結論に達しました-親が亡くなったときに子供に通知するPOSIX互換の方法はありません。だから私は次善の策を練り上げた-子投票をした。

親プロセスが(何らかの理由で)終了すると、子の親プロセスはプロセス1になります。子が定期的に単純にポーリングする場合、親が1であるかどうかを確認できます。

これは素晴らしいことではありませんが、機能し、このページの他の場所で提案されているTCPソケット/ロックファイルポーリングソリューションよりも簡単です。

66
Schof

「子」で「元の」コードを実行し、「親」で「生成された」コードを実行することでこれを達成しました(つまり、fork()の後にテストの通常の意味を逆にします)。次に、「生成された」コードでSIGCHLDをトラップします...

あなたのケースでは不可能かもしれませんが、うまくいくとかわいいかもしれません。

34
dmckee

子プロセスを変更できない場合は、次のようなものを試すことができます。

int pipes[2];
pipe(pipes)
if (fork() == 0) {
    close(pipes[1]); /* Close the writer end in the child*/
    dup2(0, pipes[0]); /* Use reader end as stdin */
    exec("sh -c 'set -o monitor; child_process & read dummy; kill %1'")
}

close(pipes[0]); /* Close the reader end in the parent */

これにより、ジョブ制御が有効になっているシェルプロセス内から子が実行されます。子プロセスはバックグラウンドで生成されます。シェルは、改行(またはEOF)を待ってから、子を殺します。

理由が何であれ、親が死亡すると、パイプの端を閉じます。子シェルは、読み取りからEOFを取得し、バックグラウンドの子プロセスを強制終了します。

29
Phil Rutschman

完全を期すために。 macOSでは、kqueueを使用できます。

void noteProcDeath(
    CFFileDescriptorRef fdref, 
    CFOptionFlags callBackTypes, 
    void* info) 
{
    // LOG_DEBUG(@"noteProcDeath... ");

    struct kevent kev;
    int fd = CFFileDescriptorGetNativeDescriptor(fdref);
    kevent(fd, NULL, 0, &kev, 1, NULL);
    // take action on death of process here
    unsigned int dead_pid = (unsigned int)kev.ident;

    CFFileDescriptorInvalidate(fdref);
    CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example

    int our_pid = getpid();
    // when our parent dies we die as well.. 
    LOG_INFO(@"exit! parent process (pid %u) died. no need for us (pid %i) to stick around", dead_pid, our_pid);
    exit(EXIT_SUCCESS);
}


void suicide_if_we_become_a_zombie(int parent_pid) {
    // int parent_pid = getppid();
    // int our_pid = getpid();
    // LOG_ERROR(@"suicide_if_we_become_a_zombie(). parent process (pid %u) that we monitor. our pid %i", parent_pid, our_pid);

    int fd = kqueue();
    struct kevent kev;
    EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
    kevent(fd, &kev, 1, NULL, 0, NULL);
    CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, noteProcDeath, NULL);
    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
    CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}
14
neoneye

Linuxでは、次のように、子に親の死信号をインストールできます。

#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
#include <signal.h> // signals
#include <unistd.h> // fork()
#include <stdio.h>  // perror()

// ...

pid_t ppid_before_fork = getpid();
pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() != ppid_before_fork)
        exit(1);
    // continue child execution ...

フォークの前に親プロセスIDを保存し、 prctl() の後に子でテストすると、 prctl() と子を呼び出したプロセスの終了との間の競合状態がなくなります。

また、新しく作成された独自の子では、子の親の死亡シグナルがクリアされることに注意してください。 execve()の影響を受けません。

すべての orphans の採用を担当するシステムプロセスがPID 1を持っていることが確実な場合、そのテストは単純化できます。

pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() == 1)
        exit(1);
    // continue child execution ...

ただし、そのシステムプロセスがinitであり、PID 1を使用することは移植性がありません。 POSIX.1-2008指定

呼び出し元プロセスの既存のすべての子プロセスおよびゾンビプロセスの親プロセスIDは、実装定義のシステムプロセスのプロセスIDに設定されます。つまり、これらのプロセスは特別なシステムプロセスに継承されます。

従来、すべてのオーファンを採用しているシステムプロセスはPID 1、つまりinitです。これはすべてのプロセスの祖先です。

LinuxFreeBSD などの最新のシステムでは、別のプロセスがその役割を持っている可能性があります。たとえば、Linuxでは、プロセスは prctl(PR_SET_CHILD_SUBREAPER, 1) を呼び出して、その子孫のすべてのオーファンを継承するシステムプロセスとして確立します(Fedora 25の example を参照)。

12
maxschlepzig

子プロセスには、親プロセスとの間のパイプがありますか?その場合、書き込み中にSIGPIPEを受け取るか、読み取り中にEOFを取得します-これらの状態を検出できます。

11
MarkR

ここでの別の答えに触発されて、次のすべてのPOSIXソリューションを思いつきました。一般的な考え方は、親と子の間に中間プロセスを作成することです。これには、1つの目的があります。親が死んだときに通知し、子を明示的に殺すことです。

このタイプのソリューションは、子のコードを変更できない場合に役立ちます。

int p[2];
pipe(p);
pid_t child = fork();
if (child == 0) {
    close(p[1]); // close write end of pipe
    setpgid(0, 0); // prevent ^C in parent from stopping this process
    child = fork();
    if (child == 0) {
        close(p[0]); // close read end of pipe (don't need it here)
        exec(...child process here...);
        exit(1);
    }
    read(p[0], 1); // returns when parent exits for any reason
    kill(child, 9);
    exit(1);
}

この方法には2つの小さな注意事項があります。

  • 意図的に中間プロセスを強制終了すると、親が死亡しても子は強制終了されません。
  • 子が親の前に終了した場合、中間プロセスは元の子pidを強制終了しようとします。これにより、別のプロセスを参照できるようになります。 (これは、中間プロセスでより多くのコードを使用して修正できます。)

余談ですが、私が使用している実際のコードはPythonです。完全を期すためです。

def run(*args):
    (r, w) = os.pipe()
    child = os.fork()
    if child == 0:
        os.close(w)
        os.setpgid(0, 0)
        child = os.fork()
        if child == 0:
            os.close(r)
            os.execl(args[0], *args)
            os._exit(1)
        os.read(r, 1)
        os.kill(child, 9)
        os._exit(1)
    os.close(r)
10
Greg Hewgill

標準のPOSIX呼び出しのみを使用することを保証することは不可能だと思います。実生活のように、子供が生まれると、それ自身の生活があります。

isは、親プロセスがほとんどの終了イベントをキャッチし、その時点で子プロセスを強制終了しようとする可能性がありますが、キャッチできないものが常にいくつかあります。

たとえば、SIGKILLをキャッチできるプロセスはありません。カーネルがこのシグナルを処理すると、指定されたプロセスは何も通知せずに終了します。

類推を拡張するために-それを行う唯一の他の標準的な方法は、親がいなくなったことがわかったときに子供が自殺することです。

prctl(2)を使用してLinux専用の方法があります-他の回答を参照してください。

7
Alnitak

他の人が指摘したように、親が終了するときに親pidが1になることを頼ることは移植性がありません。特定の親プロセスIDを待つ代わりに、IDが変更されるのを待ちます。

pit_t pid = getpid();
switch (fork())
{
    case -1:
    {
        abort(); /* or whatever... */
    }
    default:
    {
        /* parent */
        exit(0);
    }
    case 0:
    {
        /* child */
        /* ... */
    }
}

/* Wait for parent to exit */
while (getppid() != pid)
    ;

フルスピードでポーリングしたくない場合は、必要に応じてマイクロスリープを追加します。

このオプションは、パイプを使用したり、信号に依存するよりも簡単に思えます。

6
user2168915

トラップハンドラをインストールして、SIGINTをキャッチします。これにより、子プロセスがまだ生きている場合にそれを強制終了しますが、SIGKILLをキャッチしない他のポスターは正しいです。

排他的アクセスで.lockfileを開き、子がそれを開こうとしてポーリングするようにします-開くことに成功した場合、子プロセスは終了するはずです

4
Paul Betts

このソリューションは私のために働いた:

  • 子にstdinパイプを渡します-データをストリームに書き込む必要はありません。
  • 子は、EOFまでstdinから無期限に読み取ります。 EOFは、親がなくなったことを示します。
  • これは、親がいなくなったときを検出するための簡単でポータブルな方法です。親がクラッシュしても、OSはパイプを閉じます。

これは、親が生存している場合にのみその存在が意味をなすワーカー型プロセス用でした。

4
joonas.fi

迅速で汚い方法は、子と親の間にパイプを作成することだと思います。親が終了すると、子はSIGPIPEを受け取ります。

3
Yefei

一部のポスターでは、すでにパイプとkqueueに言及しています。実際には、socketpair()呼び出しによって、接続されたnixドメインソケットのペアを作成することもできます。ソケットタイプはSOCK_STREAMである必要があります。

2つのソケットファイル記述子fd1、fd2があるとします。 fork()では、fdsを継承する子プロセスを作成します。親ではfd2を閉じ、子ではfd1を閉じます。これで、各プロセスは、POLLINイベントに対して、poll()残りの開いているfdを独自に終了できます。通常のライフタイム中に各サイドが明示的にclose()そのfdをしない限り、POLLHUPフラグが(クリーンであるかどうかに関係なく)相手の終了を示すはずです。このイベントが通知されると、子供は何をすべきか(たとえば死ぬこと)を決定できます。

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    int sv[2];        /* sv[0] for parent, sv[1] for child */
    socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

    pid_t pid = fork();

    if ( pid > 0 ) {  /* parent */
        close(sv[1]);
        fprintf(stderr, "parent: pid = %d\n", getpid());
        sleep(100);
        exit(0);

    } else {          /* child */
        close(sv[0]);
        fprintf(stderr, "child: pid = %d\n", getpid());

        struct pollfd mon;
        mon.fd = sv[1];
        mon.events = POLLIN;

        poll(&mon, 1, -1);
        if ( mon.revents & POLLHUP )
            fprintf(stderr, "child: parent hung up\n");
        exit(0);
    }
}

上記の概念実証コードをコンパイルして、./a.out &などの端末で実行できます。さまざまな信号によって親PIDを強制終了する実験を行うのに約100秒かかります。さもなければ、単に終了します。いずれの場合でも、「子:親が電話を切った」というメッセージが表示されるはずです。

SIGPIPEハンドラーを使用するメソッドと比較すると、このメソッドはwrite()呼び出しを試行する必要がありません。

このメソッドもsymmetricです。つまり、プロセスは同じチャネルを使用して互いの存在を監視できます。

このソリューションは、POSIX関数のみを呼び出します。これをLinuxとFreeBSDで試しました。他のUnixでも動作するはずですが、実際にはテストしていません。

こちらもご覧ください:

  • Linuxのマニュアルページのunix(7)、FreeBSDのunix(4)、Linuxのpoll(2)socketpair(2)socket(7)
3
Cong Ma

他の人に関連する場合、C++からフォークされた子プロセスでJVMインスタンスを生成するとき、親プロセスが完了した後にJVMインスタンスを適切に終了させる唯一の方法は、次のことを行うことでした。これが最善の方法でなかった場合、誰かがコメントでフィードバックを提供できることを願っています。

1)execvを介してJavaアプリを起動する前に、推奨されるように分岐した子プロセスでprctl(PR_SET_PDEATHSIG, SIGHUP)を呼び出します。

2)親PIDが1になるまでポーリングするJavaアプリケーションにシャットダウンフックを追加してから、ハードRuntime.getRuntime().halt(0)を実行します。ポーリングは、psコマンドを実行する別のシェルを起動することで実行されます( LinuxでJavaまたはJRubyでPIDを見つけるにはどうすればよいですか? )。

130118を編集:

堅牢なソリューションではなかったようです。私はまだ何が起こっているのかという微妙な意味を理解するのに少し苦労していますが、これらのアプリケーションを画面/ SSHセッションで実行しているときに時々Orphan JVMプロセスを取得していました。

JavaアプリでPPIDをポーリングする代わりに、シャットダウンフックにクリーンアップを実行させた後、上記のように強制停止しました。その後、すべてを終了するときに、生成された子プロセスのC++親アプリでwaitpidを呼び出すようにしました。子プロセスは確実に終了し、親は既存の参照を使用して子プロセスが終了するようにするため、これはより堅牢なソリューションのようです。これを、親プロセスが満足するたびに終了し、終了する前に親が孤立していたかどうかを子供に理解させようとした以前のソリューションと比較してください。

1
jasterm007

POSIX では、exit()_exit()、および_Exit()関数は次のように定義されます。

  • プロセスが制御プロセスの場合、SIGHUPシグナルは、呼び出しプロセスに属する制御端末のフォアグラウンドプロセスグループ内の各プロセスに送信されます。

そのため、親プロセスをそのプロセスグループの制御プロセスとする場合、親が終了すると、子はSIGHUPシグナルを受け取る必要があります。親がクラッシュしたときにそれが起こるかどうかは確かではありませんが、そうなると思います。確かに、非クラッシュの場合、それはうまく動作するはずです。

基本定義(定義)セクション、およびexit()およびsetsid()およびsetpgrp()のシステムサービス情報を含む、かなり多くの細かい印刷物を読む必要があることに注意してください。完全な画像を取得します。 (そうだ!)

1

たとえば、pid 0にシグナルを送信する場合

kill(0, 2); /* SIGINT */

そのシグナルはプロセスグループ全体に送信されるため、子を効果的に殺します。

次のようなもので簡単にテストできます。

(cat && kill 0) | python

^ Dを押すと、"Terminated"というテキストが表示されます。これは、Pythonインタープリターが、stdinが閉じられたために終了しただけでなく、実際に強制終了されたことを示します。

1

歴史的に、UNIX v7から、プロセスシステムはプロセスの親IDをチェックすることによりプロセスの孤立を検出しました。私が言うように、歴史的に、init(8)システムプロセスは、ただ一つの理由で特別なプロセスです:それは死ぬことができません。新しい親プロセスIDの割り当てを処理するカーネルアルゴリズムはこの事実に依存しているため、死ぬことはありません。プロセスがそのexit(2)呼び出しを実行すると(プロセスシステムコールまたは信号などを送信する外部タスクによる)、カーネルはこのプロセスのすべての子にinitプロセスのidを親プロセスとして再割り当てします。 id。これにより、テストが最も簡単になり、プロセスが孤立したかどうかを最もポータブルに知ることができます。 getppid(2)システムコールの結果を確認し、それがinit(2)プロセスのプロセスIDである場合、システムコールの前にプロセスは孤立しました。

このアプローチから、問題につながる可能性のある2つの問題が発生します。

  • まず、initプロセスを任意のユーザープロセスに変更する可能性があります。そのため、initプロセスが常にすべての孤立プロセスの親になることを保証するにはどうすればよいでしょうか。さて、exitシステムコールコードでは、呼び出しを実行しているプロセスがinitプロセス(pidが1に等しいプロセス)であるかどうかを確認する明示的なチェックがあります。プロセス階層を維持できるようになります)。そのため、initプロセスがexit(2)呼び出しを行うことは許可されません。
  • 次に、上記の基本テストに競合状態があります。 InitプロセスのIDは歴史的に1であると想定されていますが、POSIXのアプローチでは保証されていません。これを行うPOSIX実装はほとんどありません。元のUNIX派生システムでは、getppid(2)システムコールの応答として1があれば、プロセスが孤立していると見なすことができます。チェックする別の方法は、フォークの直後にgetppid(2)を作成し、その値を新しい呼び出しの結果と比較することです。両方の呼び出しがアトミックではなく、親プロセスはfork(2)の後、最初のgetppid(2)システムコールの前に終了する可能性があるため、これは単にすべての場合に機能しません。 processparent id only changes once, when its parent does anexit(2)call, so this should be enough to check if thegetppid(2)result changed between calls to see that parent process has exit. This test is not valid for the actual children of the init process, because they are always children ofinit(8) `。ただし、これらのプロセスは親を持たないと安全に仮定できます(システムでinitプロセスを代用する場合を除く) )
0
Luis Colorado

7年が過ぎましたが、開発中にwebpack-dev-serverを起動し、バックエンドプロセスが停止したときにそれを強制終了する必要があるSpringBootアプリケーションを実行しているため、この問題に遭遇しました。

Runtime.getRuntime().addShutdownHookを使用しようとしましたが、Windows 10では機能しましたが、Windows 7では機能しませんでした。

プロセスが終了するか、両方のWindowsバージョンで正常に動作するInterruptedExceptionを待つ専用スレッドを使用するように変更しました。

private void startWebpackDevServer() {
    String cmd = isWindows() ? "cmd /c gradlew webPackStart" : "gradlew webPackStart";
    logger.info("webpack dev-server " + cmd);

    Thread thread = new Thread(() -> {

        ProcessBuilder pb = new ProcessBuilder(cmd.split(" "));
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.directory(new File("."));

        Process process = null;
        try {
            // Start the node process
            process = pb.start();

            // Wait for the node process to quit (blocking)
            process.waitFor();

            // Ensure the node process is killed
            process.destroyForcibly();
            System.setProperty(WEBPACK_SERVER_PROPERTY, "true");
        } catch (InterruptedException | IOException e) {
            // Ensure the node process is killed.
            // InterruptedException is thrown when the main process exit.
            logger.info("killing webpack dev-server", e);
            if (process != null) {
                process.destroyForcibly();
            }
        }

    });

    thread.start();
}
0
Ido Ran

2つのソリューションが見つかりましたが、どちらも完璧ではありません。

1. SIGTERMシグナルを受信すると、kill(-pid)ですべての子を殺します。
明らかに、このソリューションは「kill -9」を処理できませんが、すべての子プロセスを記憶する必要がないため、ほとんどの場合非常に簡単に機能します。


    var childProc = require('child_process').spawn('tail', ['-f', '/dev/null'], {stdio:'ignore'});

    var counter=0;
    setInterval(function(){
      console.log('c  '+(++counter));
    },1000);

    if (process.platform.slice(0,3) != 'win') {
      function killMeAndChildren() {
        /*
        * On Linux/Unix(Include Mac OS X), kill (-pid) will kill process group, usually
        * the process itself and children.
        * On Windows, an JOB object has been applied to current process and children,
        * so all children will be terminated if current process dies by anyway.
        */
        console.log('kill process group');
        process.kill(-process.pid, 'SIGKILL');
      }

      /*
      * When you use "kill pid_of_this_process", this callback will be called
      */
      process.on('SIGTERM', function(err){
        console.log('SIGTERM');
        killMeAndChildren();
      });
    }

同様に、process.exitをどこかで呼び出すと、上記のように 'exit'ハンドラーをインストールできます。注:Ctrl + Cと突然のクラッシュは、プロセスグループを強制終了するためにOSによって自動的に処理されているため、ここではもうありません。

2. chjj/pty.js を使用して、制御端末が接続されたプロセスを生成します。
とにかくkill -9で現在のプロセスを強制終了すると、すべての子プロセスも自動的に強制終了されます(OSによって?)。現在のプロセスは端末のもう一方の側を保持しているため、現在のプロセスが停止した場合、子プロセスはSIGPIPEを取得するためだと思います。


    var pty = require('pty.js');

    //var term =
    pty.spawn('any_child_process', [/*any arguments*/], {
      name: 'xterm-color',
      cols: 80,
      rows: 30,
      cwd: process.cwd(),
      env: process.env
    });
    /*optionally you can install data handler
    term.on('data', function(data) {
      process.stdout.write(data);
    });
    term.write(.....);
    */

0
osexp2003

これを行うLinux固有の別の方法は、新しいPID名前空間に親を作成することです。その後、そのネームスペースでPID 1になり、終了すると、そのすべての子がSIGKILLで即座に削除されます。

残念ながら、新しいPID名前空間を作成するには、CAP_SYS_ADMINが必要です。ただし、この方法は非常に効果的であり、親の最初の起動以降、親または子に実際の変更を加える必要はありません。

clone(2)pid_namespaces(7) 、および nshare(2) を参照してください。

0
Omnifarious

私は、端末制御とセッションを悪用することにより、3つのプロセスでポータブルな非ポーリングソリューションを実行することができました。これはメンタルオナニーですが、動作します。

トリックは次のとおりです。

  • プロセスAが開始されます
  • プロセスAはパイプPを作成します(パイプPからは読み取りません)
  • プロセスAはプロセスBに分岐します
  • プロセスBは新しいセッションを作成します
  • プロセスBは、その新しいセッションに仮想端末を割り当てます
  • プロセスBはSIGCHLDハンドラーをインストールして、子プロセスの終了時に停止します
  • プロセスBはSIGPIPEハンドラーを設定します
  • プロセスBはプロセスCに分岐します
  • プロセスCは必要なことは何でも行います(たとえば、変更されていないバイナリをexec()するか、ロジックを実行します)
  • プロセスBはパイプPに書き込みます(そのようにブロックします)
  • プロセスAはプロセスBでwait()し、終了すると終了します

その方法:

  • プロセスAが停止した場合:プロセスBはSIGPIPEを取得して停止します
  • プロセスBが死んだ場合:プロセスAのwait()が戻って死ぬと、プロセスCはSIGHUPを取得します(端末が接続されたセッションのセッションリーダーが死ぬと、フォアグラウンドプロセスグループのすべてのプロセスがSIGHUPを取得するため)
  • プロセスCが停止した場合:プロセスBはSIGCHLDを取得して停止するため、プロセスAは停止します

欠点:

  • プロセスCはSIGHUPを処理できません
  • プロセスCは別のセッションで実行されます
  • プロセスCは脆弱なセットアップを壊すため、セッション/プロセスグループAPIを使用できません
  • そのような操作ごとに端末を作成することは、これまでで最高のアイデアではありません
0
Marek Dopiera

親が死亡すると、孤児のPPIDが1に変わります。自分のPPIDのみを確認する必要があります。ある意味では、これは前述のポーリングです。そのためのシェルピースを次に示します。

check_parent () {
      parent=`ps -f|awk '$2=='$PID'{print $3 }'`
      echo "parent:$parent"
      let parent=$parent+0
      if [[ $parent -eq 1 ]]; then
        echo "parent is dead, exiting"
        exit;
      fi
}


PID=$$
cnt=0
while [[ 1 = 1 ]]; do
  check_parent
  ... something
done
0
alex K