Question

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 le faire correctement?

Une question similaire sur stackoverflow:

Une question similaire sur stackoverflow pour Windows :

Était-ce utile?

La solution

L'enfant 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 () comme suit :

prctl (PR_SET_PDEATHSIG, SIGHUP);

Voir man 2 prctl pour plus de détails.

Éditer: Ceci est réservé à Linux

Autres conseils

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

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. Alors, j'ai bafouillé la meilleure chose à faire: avoir le sondage auprès des enfants.

Quand un processus parent meurt (pour une raison quelconque), le processus parent de l'enfant devient un 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 génial, mais cela fonctionne et c’est plus simple que les solutions d’interrogation socket / lockfile TCP suggérées ailleurs sur cette page.

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

Peut-être pas possible dans votre cas, mais mignon quand ça marche.

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

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

Lorsque le parent meurt, quelle que soit 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.

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

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

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 stockage de l'ID de processus parent avant le fork et son test dans l'enfant après prctl () élimine une condition 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 un execve () .

Ce test peut être simplifié si nous sommes certains que le processus système est chargé d’adopter tous les orphelins. a 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 en tant que init et avoir le PID 1 n'est pas portable, cependant. POSIX.1-2008 spécifie :

  

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 oeuvre. Autrement dit, 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 (voir un exemple sur Fedora 25).

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, ayant un seul objectif: notifier la mort du parent 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 compléter:

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)

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 né, il a sa propre vie.

Il est possible pour le processus parent de capturer la plupart des événements de terminaison possibles et de tenter de supprimer le processus enfant à ce stade, mais il en reste toujours quelques-uns qui ne peuvent pas être capturés.

Par exemple, aucun processus ne peut attraper un SIGKILL . Lorsque le noyau traite 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 avec prctl (2) - voir les autres réponses.

Comme d'autres personnes l'ont fait remarquer, 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 à pleine vitesse.

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

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 un accès exclusif et demandez à l'enfant d'interroger le sondage en essayant de l'ouvrir - si l'ouverture réussit, le processus enfant doit se fermer

Cette solution a fonctionné pour moi:

  • Transmettez le tube 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 signale que le parent est parti.
  • Il s'agit d'un moyen infaillible et portable de détecter le départ du parent. Même si le parent tombe en panne, le système d’exploitation ferme le tuyau.

Il s’agissait d’un processus de type travailleur dont l’existence n’avait de sens que lorsque le parent était en vie.

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

Certaines affiches ont déjà mentionné les tuyaux 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. Désormais, chaque processus peut poll () le fd ouvert restant de son côté pour l'événement POLLIN . Tant que chaque côté ne fait pas explicitement close () son fd pendant sa durée de vie normale, vous pouvez être presque sûr qu'un indicateur POLLHUP doit indiquer la fin de l'autre (peu importe la suppression). ou pas). Aprè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 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, le message "enfant: parent raccroché" devrait s'afficher.

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 aussi:

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

Sous POSIX , le 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 au 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 lorsqu’il quitte. 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 () - pour obtenir une image complète. (Je le ferais aussi!)

Si vous envoyez un signal au pid 0, en utilisant par exemple

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

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

Vous pouvez le tester facilement avec quelque chose comme:

(cat && kill 0) | python

Si vous appuyez ensuite sur ^ D, le texte "Terminé" indique que l'interpréteur Python a bien été tué, au lieu d'être simplement quitté car stdin est fermé.

Si cela concerne tout le monde, lorsque j'engendre des instances JVM dans des processus enfants fourchis à partir de C ++, la seule façon pour que les instances JVM se terminent correctement 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 un Runtime.getRuntime (). halt (0) . La scrutation est effectuée en lançant un shell distinct qui exécute la commande ps (voir: Comment trouver mon PID en Java ou 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 il m'arrivait encore parfois d'avoir des processus JVM orphelins lors de l'exécution de ces applications dans des sessions screen / SSH.

Au lieu d’interroger le PPID dans l’application Java, j’ai simplement demandé au hook d’arrêt d’effectuer un nettoyage suivi d’un arrêt définitif, comme ci-dessus. Ensuite, j'ai veillé à appeler 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.

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 un morceau de coquille 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

J'ai trouvé 2 solutions, les deux n'étant pas parfaites.

1. Tuez tous les enfants par kill (-pid) lors de 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 créer votre processus en contrôlant borne attachée.
De toute façon, même lorsque vous tuez -9, tous les processus enfants sont automatiquement tués (par le système d’exploitation?). Je suppose que parce que le processus en cours a un autre côté du terminal, donc si le processus en cours meurt, le processus enfant obtiendra SIGPIPE, il meurt donc.


    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(.....);
    */

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

Le truc, c'est:

  • le processus A est lancé
  • processus A crée un tuyau P (et ne le lit jamais)
  • processus A fourches dans 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 lorsque l'enfant quitte
  • processus B définit un gestionnaire SIGPIPE
  • le processus B se transforme 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 canal P (et le bloque de cette façon)
  • processus A wait () s sur le processus B et quitte quand il meurt

Ainsi:

  • si le processus A meurt: le processus B obtient un SIGPIPE et meurt
  • si le processus B meurt: le processus A attend () revient 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, 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
  • process 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

Même si 7 ans se sont écoulés, je viens de rencontrer ce problème car je lance une application SpringBoot qui doit démarrer webpack-dev-server pendant le développement et doit la supprimer lorsque le processus d’arrêt s’arrête.

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 fermeture du processus ou 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();
}

Historiquement, à partir d'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. quand un processus exécute son appel exit (2) (au moyen d'un appel système de processus ou par une tâche externe lui envoyant un signal, etc.), le noyau réattribue à tous les enfants de ce processus l'id du init process comme identifiant de processus parent. Cela conduit au test le plus simple et au moyen le plus portable de savoir si un processus est devenu orphelin. Il suffit de vérifier le résultat de l'appel système getppid (2) et s'il s'agit de l'ID de processus du processus init (2) , le processus est devenu orphelin avant l'appel système.

Cette approche peut donner lieu à deux problèmes:

  • Tout d'abord, nous avons la possibilité de changer le processus init en n'importe quel processus utilisateur. Comment pouvons-nous nous assurer que le processus init sera toujours le parent de tous les processus orphelins? Eh bien, dans le code d’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 tel est le cas, le noyau panique ( Il ne devrait plus être en mesure de maintenir la hiérarchie des processus), il est donc interdit au processus init de faire un appel exit (2) .
  • Deuxièmement, il existe une condition de concurrence critique dans le test de base exposé ci-dessus. Historiquement, l'identifiant de processus init est supposé être 1 , mais cela 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 de l'unix d'origine qu'avoir 1 en réponse à getppid (2) est suffisant pour 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 ensemble et le processus parent peut mourir après le fork (2) et avant le premier getppid (2) appel système. Le processus id parent ne change qu'une fois, lorsque son parent effectue un appel exit (2) , cela devrait donc suffire à vérifier si le résultat getppid (2) changé entre les appels pour voir ce processus parent a quitter. Ce test n’est pas valable pour les enfants réels du processus init, car ils sont toujours enfants de init (8) `, mais vous pouvez supposer en toute sécurité que ces processus n’ont pas non plus de parent (sauf lorsque vous remplacez un système). le processus init)

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 supprimé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 unshare (2) .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top