web-dev-qa-db-fra.com

Comment faire en sorte que le processus enfant meure après la sortie du parent?

Supposons que j'ai un processus qui génère exactement un processus enfant. Maintenant, lorsque le processus parent se termine pour une raison quelconque (normalement ou anormalement, par kill, ^ C, affirmer un échec ou toute autre chose), je veux que le processus enfant meure. Comment faire ça correctement?


Une question similaire sur stackoverflow:


Une question similaire sur stackoverflow pour Windows :

199
Paweł Hajdan

Child peut demander au noyau de fournir SIGHUP (ou un autre signal) lorsque le parent meurt en spécifiant l'option PR_SET_PDEATHSIG dans prctl() syscall comme ceci:

prctl(PR_SET_PDEATHSIG, SIGHUP);

Voir man 2 prctl pour plus de détails.

Edit: Ceci est uniquement Linux

174
qrdl

J'essaie de résoudre le même problème et, comme mon programme doit fonctionner sous OS X, la solution exclusivement Linux ne me convient pas.

Je suis arrivé à la même conclusion que les autres personnes de cette page: il n’existe pas de moyen compatible avec POSIX de prévenir un enfant du décès d’un parent. Donc, j'ai caché la meilleure chose à faire: avoir le sondage auprès des enfants.

Lorsqu'un processus parent décède (pour une raison quelconque), le processus parent de l'enfant devient processus 1. Si l'enfant interroge simplement de temps en temps, il peut vérifier si son parent est 1. Si c'est le cas, l'enfant doit quitter.

Ce n’est pas formidable, mais cela fonctionne et c’est plus simple que les solutions d’interrogation socket/lockfile TCP suggérées plus loin dans cette page.

66
Schof

J’ai atteint cet objectif dans le passé en exécutant le code "original" dans le "enfant" et le code "généré" dans le "parent" (c’est-à-dire que vous inversez le sens habituel du test après fork()). Puis piéger SIGCHLD dans le code "engendré" ...

Peut-être pas possible dans votre cas, mais mignon quand cela fonctionne.

34
dmckee

Si vous ne parvenez pas à modifier le processus enfant, vous pouvez essayer l'une des solutions suivantes:

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 */

Cela exécute l'enfant à partir d'un processus Shell avec le contrôle de travail activé. Le processus enfant est généré en arrière-plan. Le shell attend une nouvelle ligne (ou un EOF), puis tue l'enfant.

Quand le parent meurt, peu importe la raison, il ferme le bout du tuyau. Le shell enfant obtiendra un EOF de la lecture et procédera à la suppression du processus enfant en arrière-plan.

29
Phil Rutschman

Par souci d'exhaustivité. Sur macOS, vous pouvez utiliser 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

Sous Linux, vous pouvez installer un signal de décès parent dans l’enfant, par exemple:

#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 ...

Notez que le fait de stocker l'ID de processus parent avant la fourchette et de le tester dans l'enfant après prctl() élimine une situation de concurrence critique entre prctl() et la sortie du processus qui a appelé l'enfant.

Notez également que le signal de décès du parent de l’enfant est effacé chez les enfants nouvellement créés. Il n'est pas affecté par une execve().

Ce test peut être simplifié si nous sommes certains que le processus système responsable de l'adoption de tous les orphelins possède le 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 ...

S'appuyer sur ce processus système étant init et avoir le PID 1 n'est pas portable, cependant. spécifie POSIX.1-2008 :

L'ID de processus parent de tous les processus enfants et processus zombies existants du processus appelant doit être défini sur l'ID de processus d'un processus système défini par la mise en œuvre. C'est-à-dire que ces processus doivent être hérités par un processus système spécial.

Traditionnellement, le processus système adoptant tous les orphelins est le PID 1, c’est-à-dire init - qui est l’ancêtre de tous les processus.

Sur des systèmes modernes tels que Linux ou FreeBSD , un autre processus pourrait avoir ce rôle. Par exemple, sous Linux, un processus peut appeler prctl(PR_SET_CHILD_SUBREAPER, 1) pour s’établir en tant que processus système qui hérite de tous les orphelins de ses descendants (cf. un exemple sur Fedora 25).

12
maxschlepzig

Le processus enfant a-t-il un tuyau vers/depuis le processus parent? Si tel est le cas, vous recevrez un message SIGPIPE si vous écrivez ou obtenez EOF lors de la lecture - ces conditions peuvent être détectées.

11
MarkR

Inspiré par une autre réponse, je suis arrivé à la solution tout POSIX suivante. L'idée générale est de créer un processus intermédiaire entre le parent et l'enfant, qui n'a qu'un seul objectif: avertir quand le parent meurt et tuer explicitement l'enfant.

Ce type de solution est utile lorsque le code de l'enfant ne peut pas être modifié.

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);
}

Il y a deux petites mises en garde avec cette méthode:

  • Si vous tuez délibérément le processus intermédiaire, l'enfant ne sera pas tué à la mort du parent.
  • Si l'enfant quitte avant le parent, le processus intermédiaire essaiera de tuer le pid enfant d'origine, ce qui pourrait maintenant faire référence à un processus différent. (Cela pourrait être corrigé avec plus de code dans le processus intermédiaire.)

En passant, le code que j'utilise est en Python. La voici pour la complétude:

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

Je ne crois pas qu'il soit possible de garantir cela en utilisant uniquement les appels POSIX standard. Comme dans la vraie vie, une fois qu'un enfant est engendré, il a sa propre vie.

Il est possible de permettre au processus parent d'attraper la plupart des événements de terminaison possibles et de tenter de tuer le processus enfant à ce moment-là, mais il y en a toujours qui peuvent ' t être attrapé.

Par exemple, aucun processus ne peut attraper un SIGKILL. Lorsque le noyau gère ce signal, le processus spécifié sera tué sans aucune notification à ce processus.

Pour étendre l'analogie, la seule autre façon habituelle de le faire est que l'enfant se suicide lorsqu'il découvre qu'il n'a plus de parent.

Il existe un moyen de le faire uniquement avec Linux à prctl(2) - voir les autres réponses.

7
Alnitak

Comme d'autres personnes l'ont souligné, compter sur le pid parent pour devenir 1 lorsque le parent quitte n'est pas portable. Au lieu d'attendre un ID de processus parent spécifique, attendez simplement que l'ID change:

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)
    ;

Ajoutez un micro-sommeil à votre guise si vous ne souhaitez pas interroger à grande vitesse.

Cette option me semble plus simple que d'utiliser un tuyau ou de compter sur des signaux.

6
user2168915

Installez un gestionnaire de pièges pour capturer SIGINT, qui tue votre processus enfant s'il est toujours en vie, bien que d'autres affiches indiquent correctement qu'il ne capturera pas SIGKILL.

Ouvrez un fichier .lock avec accès exclusif et demandez à l'enfant d'interroger le fichier en essayant de l'ouvrir. Si l'ouverture réussit, le processus enfant doit se fermer.

4
Paul Betts

Cette solution a fonctionné pour moi:

  • Passez le tuyau stdin à l'enfant - vous n'avez pas à écrire de données dans le flux.
  • L'enfant lit indéfiniment de stdin jusqu'à EOF. Un EOF indique que le parent est parti.
  • C'est un moyen infaillible et portable de détecter le départ du parent. Même si le parent se bloque, le système d’exploitation ferme le tuyau.

C'était pour un processus de type travailleur dont l'existence n'avait de sens que lorsque le parent était en vie.

4
joonas.fi

Je pense qu'un moyen rapide et sale est de créer un tuyau entre l'enfant et le parent. Lorsque le parent quitte, les enfants recevront un SIGPIPE.

3
Yefei

Certaines affiches ont déjà mentionné les pipes et kqueue. En fait, vous pouvez également créer une paire de sockets de domaine Unix connectés par l'appel socketpair(). Le type de socket doit être SOCK_STREAM.

Supposons que vous ayez les deux descripteurs de fichier de socket fd1, fd2. Maintenant, fork() pour créer le processus enfant qui héritera du fds. Dans le parent, vous fermez fd2 et dans l'enfant, vous fermez fd1. Maintenant, chaque processus peut poll() le fd ouvert restant de son côté pour l'événement POLLIN. Tant que chaque partie ne fait pas explicitement close() son fd pendant sa durée de vie normale, vous pouvez être à peu près sûr qu'un indicateur POLLHUP devrait indiquer la fin de l'autre (qu'elle soit propre ou non). Dès notification de cet événement, l’enfant peut décider quoi faire (par exemple, mourir).

#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);
    }
}

Vous pouvez essayer de compiler le code de validation de principe ci-dessus et l'exécuter dans un terminal tel que ./a.out &. Vous avez environ 100 secondes pour essayer de tuer le PID parent par divers signaux, sinon il va simplement sortir. Dans les deux cas, vous devriez voir le message "enfant: parent raccroché".

Comparée à la méthode utilisant le gestionnaire SIGPIPE, cette méthode ne nécessite pas l'essai de l'appel write().

Cette méthode est également symétrique , c’est-à-dire que les processus peuvent utiliser le même canal pour surveiller l’existence de chacun.

Cette solution appelle uniquement les fonctions POSIX. J'ai essayé cela sous Linux et FreeBSD. Je pense que cela devrait fonctionner sur d'autres Unix mais je n'ai pas vraiment testé.

Voir également:

  • unix(7) des pages de manuel Linux, unix(4) pour FreeBSD, poll(2), socketpair(2), socket(7) sous Linux.
3
Cong Ma

Si cela concerne tout le monde, lorsque je crée des instances JVM dans des processus enfants fourchis à partir de C++, la seule façon de terminer correctement les instances JVM une fois le processus parent terminé est de procéder comme suit. Espérons que quelqu'un puisse donner son avis dans les commentaires si ce n'était pas la meilleure façon de le faire.

1) Appelez prctl(PR_SET_PDEATHSIG, SIGHUP) sur le processus enfant créé, comme suggéré avant le lancement de l'application Java via execv, et

2) Ajoutez un point d’arrêt à l’application Java qui interroge jusqu’à ce que son PID parent soit égal à 1, puis effectuez une opération dure Runtime.getRuntime().halt(0). La scrutation est effectuée en lançant un shell séparé qui exécute la commande ps (voir: Comment trouver mon PID dans Java ou dans JRuby sous Linux? ).

EDIT 130118:

Il semble que ce n’était pas une solution robuste. Je n'arrive toujours pas à comprendre les nuances de ce qui se passe, mais parfois, j'avais toujours des processus JVM orphelins lorsque j'exécutais ces applications dans des sessions screen/SSH.

Au lieu d'interroger le PPID dans l'application Java, j'ai simplement demandé au crochet d'arrêt d'effectuer un nettoyage suivi d'un arrêt définitif, comme ci-dessus. Ensuite, j'ai veillé à invoquer waitpid dans l'application parent C++ sur le processus enfant engendré lorsqu'il était temps de tout terminer. Cela semble être une solution plus robuste, car le processus enfant s'assure qu'il se termine, tandis que le parent utilise les références existantes pour s'assurer que ses enfants se terminent. Comparez cela à la solution précédente selon laquelle le processus parent mettait fin au bon moment et que les enfants essayaient de déterminer s'ils étaient orphelins avant la fin.

1
jasterm007

Sous POSIX , les fonctions exit(), _exit() et _Exit() sont définies comme suit:

  • Si le processus est un processus de contrôle, le signal SIGHUP doit être envoyé à chaque processus du groupe de processus de premier plan du terminal de contrôle appartenant au processus appelant.

Ainsi, si vous faites en sorte que le processus parent soit un processus de contrôle pour son groupe de processus, l'enfant doit recevoir un signal SIGHUP lorsque le parent se ferme. Je ne suis pas absolument sûr que cela se produise lorsque le parent tombe en panne, mais je pense que c'est le cas. Certes, pour les cas non-crash, cela devrait bien fonctionner.

Notez que vous devrez peut-être lire beaucoup de petits caractères - y compris la section Définitions de base (Définitions), ainsi que les informations sur les services système pour exit() et setsid() et setpgrp() - à obtenir l'image complète. (Moi aussi!)

1
Jonathan Leffler

Si vous envoyez un signal au pid 0, utilisez par exemple

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

ce signal est envoyé à l'ensemble du groupe de processus, tuant ainsi l'enfant.

Vous pouvez le tester facilement avec quelque chose comme:

(cat && kill 0) | python

Si vous appuyez ensuite sur ^ D, le texte "Terminated" indique que l'interpréteur Python a bien été tué, au lieu d'être simplement quitté en raison de la fermeture de stdin.

1
Thorbiörn Fritzon

Historiquement, à partir de UNIX v7, le système de processus a détecté l'orphelinat de processus en vérifiant l'ID parent d'un processus. Comme je le disais, historiquement, le processus système init(8) est un processus spécial pour une seule raison: il ne peut pas mourir. Il ne peut pas mourir car l’algorithme du noyau pour l’attribution d’un nouvel identifiant de processus parent dépend de ce fait. lorsqu'un processus exécute son exit(2) appel (au moyen d'un appel système ou d'une tâche externe lui envoyant un signal, etc.), le noyau réaffecte à tous les enfants de ce processus l'id du processus init en tant que processus parent. id. Cela conduit au test le plus facile et au moyen le plus portable de savoir si un processus a obtenu Orphan. Il suffit de vérifier le résultat de l'appel système getppid(2) et s'il s'agit de l'identificateur de processus du processus init(2), il est alors orphelin avant l'appel système.

Deux problèmes peuvent se dégager de cette approche:

  • premièrement, nous avons la possibilité de changer le processus init en n'importe quel processus utilisateur. Comment pouvons-nous donc nous assurer que le processus init sera toujours le parent de tous les processus Orphan? Eh bien, dans le code de l'appel système exit, il y a une vérification explicite pour voir si le processus qui exécute l'appel est le processus init (le processus avec pid égal à 1) et si c'est le cas, le noyau panique (il ne devrait pas être capable de maintenir la hiérarchie des processus), il est donc interdit au processus init de faire un appel exit(2).
  • deuxièmement, il y a une condition de concurrence dans le test de base exposé ci-dessus. Historiquement, l'identifiant de processus init est supposé être 1, mais ce n'est pas garanti par l'approche POSIX, qui indique (comme exposé dans une autre réponse) que seul l'identifiant de processus du système est réservé à cette fin. Presque aucune implémentation posix ne fait cela, et vous pouvez supposer, dans les systèmes dérivés d'unix d'origine, qu'avoir 1 comme réponse de getppid(2) appel système suffit à supposer que le processus est orphelin. Une autre façon de vérifier consiste à créer un getppid(2) juste après le fork et à comparer cette valeur au résultat d'un nouvel appel. Cela ne fonctionne tout simplement pas dans tous les cas, car les deux appels ne sont pas atomiques et le processus parent peut mourir après la fork(2) et avant le premier appel système getppid(2). Le processusparent 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) `, mais vous pouvez supposer que ces processus n’ont pas non plus de parent (sauf lorsque vous substituez dans un système le processus init )
0
Luis Colorado

Bien que 7 ans se soient écoulés, je viens tout juste de rencontrer ce problème, car je lance l'application SpringBoot qui doit démarrer webpack-dev-server pendant le développement et doit la supprimer à la fin du processus d'arrière-plan.

J'essaie d'utiliser Runtime.getRuntime().addShutdownHook mais cela fonctionnait sous Windows 10, mais pas sous Windows 7.

Je l'ai modifié pour utiliser un thread dédié qui attend la fin du processus ou pour InterruptedException qui semble fonctionner correctement sous les deux versions de Windows.

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

J'ai trouvé 2 solutions, les deux pas parfait.

1.Tuer tous les enfants par kill (-pid) à la réception du signal SIGTERM.
Évidemment, cette solution ne peut pas gérer "kill -9", mais elle fonctionne dans la plupart des cas et est très simple car elle n'a pas besoin de se souvenir de tous les processus enfants.


    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();
      });
    }

De la même manière, vous pouvez installer le gestionnaire 'exit' comme ci-dessus si vous appelez process.exit quelque part. Remarque: Ctrl + C et crash soudain ont été automatiquement traités par le système d'exploitation pour tuer le groupe de processus, donc pas plus ici.

2.Utilisez chjj/pty.js pour générer votre processus avec un terminal de contrôle connecté.
Lorsque vous supprimez le processus en cours, même de -9, tous les processus enfants seront automatiquement supprimés (par le système d’exploitation?). Je suppose que parce que le processus en cours tient un autre côté du terminal, donc si le processus en cours meurt, le processus enfant obtiendra SIGPIPE et mourra.


    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

Une autre façon de le faire, spécifique à Linux, consiste à créer le parent dans un nouvel espace de noms PID. Ce sera alors le PID 1 dans cet espace de noms, et lorsqu'il le quittera, tous ses enfants seront immédiatement tués avec SIGKILL.

Malheureusement, pour créer un nouvel espace de noms PID, vous devez disposer de CAP_SYS_ADMIN. Mais cette méthode est très efficace et ne nécessite aucun changement réel pour le parent ou les enfants au-delà du lancement initial du parent.

Voir clone (2) , pid_namespaces (7) , et nshare (2) .

0
Omnifarious

J'ai réussi à créer une solution portable sans interrogation avec 3 processus en abusant du contrôle de terminal et des sessions. Ceci est la masturbation mentale, mais fonctionne.

Le truc c'est:

  • le processus A est lancé
  • le processus A crée un tuyau P (et ne le lit jamais)
  • processus A fourches en processus B
  • le processus B crée une nouvelle session
  • le processus B alloue un terminal virtuel pour cette nouvelle session
  • process B installe le gestionnaire SIGCHLD pour qu'il meure à la sortie de l'enfant
  • le processus B définit un gestionnaire SIGPIPE
  • processus B fourches en processus C
  • le processus C fait tout ce dont il a besoin (par exemple exec () s le binaire non modifié ou exécute une logique quelconque)
  • le processus B écrit dans le tuyau P (et le bloque de cette façon)
  • process A wait () s on process B et se termine quand il meurt

De cette façon:

  • si le processus A meurt: le processus B obtient un SIGPIPE et meurt
  • si le processus B meurt: le processus A () retourne et meurt, le processus C obtient un SIGHUP (car lorsque le responsable de la session d'une session avec un terminal attaché meurt, tous les processus du groupe de processus de premier plan obtiennent un SIGHUP)
  • si le processus C meurt: le processus B obtient un SIGCHLD et meurt, alors le processus A meurt

Lacunes:

  • le processus C ne peut pas gérer SIGHUP
  • le processus C sera exécuté dans une session différente
  • le processus C ne peut pas utiliser l'API de groupe de session/processus car il va casser la configuration fragile
  • créer un terminal pour chacune de ces opérations n'est pas la meilleure idée de tous les temps
0
Marek Dopiera

Si le parent décède, le PPID des orphelins passe à 1 - il vous suffit de vérifier votre propre PPID. D'une certaine manière, il s'agit d'un sondage, mentionné ci-dessus. voici le morceau de Shell pour cela:

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