tuer un processus commencé avec popen

Après avoir ouvert un tuyau vers un processus avec popen , existe-t-il un moyen de supprimer le processus qui a été démarré? (Utiliser pclose n’est pas ce que je veux car cela va attendre la fin du processus, mais je dois le tuer.)

N’utilisez pas popen () et écrivez votre propre wrapper qui fait ce que vous voulez.

C’est assez simple à fork (), puis remplacez stdin & stdout en utilisant dup2 (), puis en appelant exec () sur votre enfant.

De cette façon, votre parent aura le PID enfant exact, et vous pouvez utiliser kill () pour cela.

Recherchez dans Google “popen2 () implementation” un exemple de code sur la façon de mettre en oeuvre ce que fait popen (). Il ne compte qu’une douzaine de lignes. Tiré de dzone.com, nous pouvons voir un exemple qui ressemble à ceci:

 #define READ 0 #define WRITE 1 pid_t popen2(const char *command, int *infp, int *outfp) { int p_stdin[2], p_stdout[2]; pid_t pid; if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) return -1; pid = fork(); if (pid < 0) return pid; else if (pid == 0) { close(p_stdin[WRITE]); dup2(p_stdin[READ], READ); close(p_stdout[READ]); dup2(p_stdout[WRITE], WRITE); execl("/bin/sh", "sh", "-c", command, NULL); perror("execl"); exit(1); } if (infp == NULL) close(p_stdin[WRITE]); else *infp = p_stdin[WRITE]; if (outfp == NULL) close(p_stdout[READ]); else *outfp = p_stdout[READ]; return pid; } 

NB: On dirait que popen2 () est ce que vous voulez, mais ma dissortingbution ne semble pas venir avec cette méthode.

Voici une version améliorée de popen2 (le crédit est dû à Sergey L.). La version publiée par slacy ne renvoie pas le PID du processus créé dans popen2, mais le PID atsortingbué à sh .

 pid_t popen2(const char **command, int *infp, int *outfp) { int p_stdin[2], p_stdout[2]; pid_t pid; if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) return -1; pid = fork(); if (pid < 0) return pid; else if (pid == 0) { close(p_stdin[WRITE]); dup2(p_stdin[READ], READ); close(p_stdout[READ]); dup2(p_stdout[WRITE], WRITE); execvp(*command, command); perror("execvp"); exit(1); } if (infp == NULL) close(p_stdin[WRITE]); else *infp = p_stdin[WRITE]; if (outfp == NULL) close(p_stdout[READ]); else *outfp = p_stdout[READ]; return pid; } 

La nouvelle version doit être appelée avec

 char *command[] = {"program", "arg1", "arg2", ..., NULL}; 

popen ne démarre pas réellement un fil, mais lance un processus. Si je regarde la définition, il ne semble pas y avoir de moyen facile d’obtenir un PID de ce processus et de le tuer. Il existe peut-être des méthodes difficiles, comme l’examen de l’arborescence des processus, mais je suppose que vous feriez mieux d’utiliser des fonctions pipe, fork et exec pour imiter le comportement de popen. Ensuite, vous pouvez utiliser le PID que vous obtenez de fork () pour tuer le processus enfant.

En fait, si le processus effectue des E / S (ce qui devrait être le cas, sinon pourquoi popen au lieu de system (3)?), Alors pclose devrait le bash avec un SIGPIPE la prochaine fois qu’il essaiera de lire ou d’écrire, et il devrait tomber bien 🙂

Le moyen évident est system (“pkill nom_processus”);

Clairement, cela pose problème si plusieurs instances du processus sont en cours d’exécution.

J’ai fait quelque chose de similaire en python, où vous pouvez tuer un sous-processus et tout sous-processus créé pour cela. C’est semblable à la solution de slacy en fait. http://www.pixelbeat.org/libs/subProcess.py

J’ai suivi l’idée de @slacy qui crée la fonction popen2.
Mais problème rencontré lorsque le processus enfant est outfp , le processus parent qui lit toujours le descripteur de fichier outfp ne revient pas de sa fonction.

Cela pourrait résoudre le problème en ajoutant un canal non utilisé étroit sur le processus parent.

 close(p_stdin[READ]); close(p_stdout[WRITE]); 

Nous pouvons obtenir le pid correct du nouveau processus en utilisant bash comme shell.

 execl("/bin/bash", "bash", "-c", command, NULL); 

Lorsque le processus enfant décède, l’appelant de la fonction popen2 doit collecter le statut du processus enfant à l’aide de l’appel pclose2 . si nous ne collectons pas ce statut, le processus enfant peut être un processus zombie lorsqu’il se termine.

C’est le code complet qui a été testé et fonctionne comme prévu.

 #define READ 0 #define WRITE 1 pid_t popen2(const char *command, int *infp, int *outfp) { int p_stdin[2], p_stdout[2]; pid_t pid; if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) return -1; pid = fork(); if (pid < 0) return pid; else if (pid == 0) { dup2(p_stdin[READ], STDIN_FILENO); dup2(p_stdout[WRITE], STDOUT_FILENO); //close unuse descriptors on child process. close(p_stdin[READ]); close(p_stdin[WRITE]); close(p_stdout[READ]); close(p_stdout[WRITE]); //can change to any exec* function family. execl("/bin/bash", "bash", "-c", command, NULL); perror("execl"); exit(1); } // close unused descriptors on parent process. close(p_stdin[READ]); close(p_stdout[WRITE]); if (infp == NULL) close(p_stdin[WRITE]); else *infp = p_stdin[WRITE]; if (outfp == NULL) close(p_stdout[READ]); else *outfp = p_stdout[READ]; return pid; } int pclose2(pid_t pid) { int internal_stat; waitpid(pid, &internal_stat, 0); return WEXITSTATUS(internal_stat); } 

Je mets simplement dans le script (bash), dans la première ligne:

 echo PID $$ 

puis je lis le pid et je l’utilise pour faire: kill (pid, 9)