matar un proceso iniciado con popen

6 minutos de lectura

matar un proceso iniciado con popen
sofia alpert

Después de abrir una tubería a un proceso con popen, ¿hay alguna manera de matar el proceso que se ha iniciado? (Utilizando pclose no es lo que quiero porque eso esperará a que termine el proceso, pero necesito matarlo).

matar un proceso iniciado con popen
slacy

no usar popen()escriba su propia envoltura que haga lo que le gustaría.

Es bastante sencillo de fork()y luego reemplace stdin & stdout
mediante el uso dup2()y luego llamando exec() en tu hijo

De esa manera, su padre tendrá el PID del niño exacto y podrá usar
kill() en ese.

Busque en Google “implementación popen2 ()” para obtener un código de muestra sobre cómo implementar lo que popen() está haciendo. Solo tiene una docena de líneas más o menos. Tomado de dzone.com podemos ver un ejemplo que se ve así:

#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: parece que popen2() es lo que desea, pero mi distribución no parece venir con este método.

  • esto no resuelve el problema de la duplicación de memoria de la bifurcación. es posible que no queramos una llamada a la bifurcación por este motivo

    – Voluntad

    7 de enero de 2012 a las 2:03

  • @phooji, ¿qué tiene que ver Python con algo?

    – Mahmud Al-Qudsi

    1 de junio de 2012 a las 20:22

  • @MahmoudAl-Qudsi: Vaya. Debo haber estado mirando demasiadas preguntas de Python. [Earlier python-related comment redacted]

    – phooji

    2 de junio de 2012 a las 18:15


  • Lo anterior necesita “cerrar (p_stdin[READ]); close(p_stdout[WRITE]);” para evitar que dos descriptores de archivos abiertos no deseados permanezcan (lo que evita que llamadas como fgets() detecten que el hijo bifurcado ha salido).

    – Chris

    15 de octubre de 2012 a las 8:41

  • El código en esta respuesta tiene un problema serio: llama exit() si execl() falla Eso hará que se llame a los controladores de salida registrados por el proceso principal y que se copien los datos de flujo almacenados en búfer desde el proceso principal a los flujos que posee el proceso principal. y si el popen2() se llama desde un proceso de C++, también se llamará a los destructores estáticos copiados del proceso principal. El código debe llamar _exit() en lugar de exit() para omitir el proceso padre exit() manipuladores

    –Andrew Henle

    5 sep 2019 a las 11:54

Aquí hay una versión mejorada de popen2 (el crédito se debe a Sergey L.). La versión publicada por slacy no devuelve el PID del proceso creado en popen2, sino el PID asignado a 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 nueva versión debe llamarse con

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

  • No vi ninguna diferencia en la parte pid; ¿Puedes actualizar los comentarios sobre la diferencia?

    – nayab

    29 de septiembre de 2014 a las 10:53


popen en realidad no inicia un hilo, sino que bifurca un proceso. Mientras miro la definición, no parece que haya una manera fácil de obtener el PID de ese proceso y eliminarlo. Puede haber formas difíciles como examinar el árbol de procesos, pero supongo que sería mejor usar funciones de tubería, bifurcación y exec para imitar el comportamiento de popen. Luego puede usar el PID que obtiene de fork () para eliminar el proceso secundario.

En realidad, si el proceso está realizando E/S (que debería ser, de lo contrario, ¿por qué popen en lugar de system(3)?), entonces pclose debería golpearlo con un SIGPIPE la próxima vez que intente leer o escribir, debería fallar muy bien 🙂

He seguido la idea de @slacy que crea la función popen2.
Pero encontré un problema cuando el proceso secundario muere, el proceso principal aún lee el descriptor del archivo outfp no regresa de la función.

Eso podría solucionarse agregando una canalización cerrada sin uso en el proceso principal.

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

Podemos obtener el pid correcto del nuevo proceso usando bash como shell.

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

Cuando el proceso hijo muere, la persona que llama a la función popen2 debe recopilar el estado del proceso secundario por llamada pclose2. si no recopilamos ese estado, el proceso secundario podría convertirse en un proceso zombi cuando finalice.

Este es el código completo que probó y funcionó como se esperaba.

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

  • En caso de que esto mate también todos los subprocesos bifurcados. Lo que veo es que si inicio una sesión SSH con popen2, sh llama a ssh y continúa ejecutando el proceso ssh incluso cuando se emite kill. ¿Hay alguna manera de capturar esos procesos también?

    – Lonko

    7 de febrero a las 9:01

1647556748 579 matar un proceso iniciado con popen
andres beca

La forma obvia es system(“pkill process_name”);

Claramente, esto es problemático si tiene más de una instancia del proceso en ejecución.

  • En caso de que esto mate también todos los subprocesos bifurcados. Lo que veo es que si inicio una sesión SSH con popen2, sh llama a ssh y continúa ejecutando el proceso ssh incluso cuando se emite kill. ¿Hay alguna manera de capturar esos procesos también?

    – Lonko

    7 de febrero a las 9:01

1647556748 906 matar un proceso iniciado con popen
pixelbeat

Hice algo similar en python, donde podía matar un subproceso y cualquier subproceso bifurcado para eso. Es similar a la solución de Slacy en realidad.
http://www.pixelbeat.org/libs/subProcess.py

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad