2012-10-01 20 views
6

Estoy codificando un shell básico en C, y estoy trabajando para suspender un proceso hijo en este momento.Después de suspender el proceso secundario con SIGTSTP, el shell no responde

Creo que mi manejador de señal es correcto, y mi proceso hijo se suspende, pero después de eso, la terminal debe regresar al proceso principal y eso no está sucediendo.

El hijo está suspendido, pero mi shell ya no registra ninguna entrada o salida. tcsetpgrp() no parece estar ayudando.

Aquí está mi manejador de la señal en mi código shell para SIGTSTP:

void suspend(int sig) { 
    pid_t pid; 
    sigset_t mask; 
    //mpid is the pgid of this shell. 
    tcsetpgrp(STDIN_FILENO, mpid); 
    tcsetpgrp(STDOUT_FILENO, mpid); 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGTSTP); 
    sigprocmask(SIG_UNBLOCK, &mask, NULL); 
    signal(SIGTSTP, SIG_DFL); 
    //active.pid is the pid of the child currently in the fg. 
    if (active.pid != 0) { 
     kill(active.pid, SIGTSTP); 
    } 
    else{ 
     //if this code is being run in the child, child calls SIGTSTP on itself. 
     pid = getpid(); 
     if (pid != 0 && pid != mpid){ 
      kill(pid, SIGTSTP); 
     } 
    } 
    signal(SIGTSTP, suspend); 
} 

Puede alguien decirme lo que estoy haciendo mal?

¿Estoy suspendiendo mi caparazón junto con el niño, y tengo que devolver stdin y stdout al shell de alguna manera? ¿Cómo haría esto?

Gracias!

Respuesta

0

tcsetpgrp es especificar cuál es el trabajo de primer plano. Cuando su caparazón engendra un trabajo en primer plano (sin &), debe crear un nuevo grupo de procesos y hacer que el trabajo en primer plano (del terminal de control, no sea lo que sea en STDIN). Luego, al presionar CTRL-Z, ese trabajo obtendrá el TSTP. Es la terminal la que suspende el trabajo, no tu caparazón. Su caparazón no debe atrapar a TSTP ni enviar TSTP a nadie.

Debe simplemente wait() para el trabajo que ha generado y detectar cuando se ha detenido (y reclamar nuevamente el grupo de primer plano y marcar el trabajo como suspendido internamente). Su comando fg haría el trabajo de pgid el grupo de procesos en primer plano de nuevo y enviar un SIGCONT a ella y esperar a que otra vez, mientras bg sería simplemente enviar el SIGCONT

+1

Gracias por la respuesta. Intenté hacer lo que dices, pero cuando me llevo mi controlador de señal, el terminal simplemente suspende al padre y vuelve a bash. Necesito que el padre siga corriendo. – user1710304

+1

Esto está completamente equivocado, no capturando SIGTSTP ciertamente haría que su caparazón se suspenda y permitirá que los procesos de los niños continúen. Necesita atraparlo para que su caparazón no se suspenda. Estoy enfrentando el mismo problema en este momento que se enfrentó anteriormente – Fingolfin

+1

@AdelQodmani, solo el grupo de proceso en primer plano del terminal recibe un SIGTSTP cuando presiona Ctrl-Z. El shell que está esperando la finalización del proceso iniciado, está en un grupo de procesos que no es el grupo de procesos en primer plano del terminal. puedes ignorar SIGTSTP si quieres, es probable que lo hagan la mayoría de las conchas. Mi punto es que necesitas jugar con el grupo de proceso en primer plano de la terminal. –

2

Es una vieja pregunta, pero todavía creo que he encontrado una respuesta.
usted no escribió el código de su padre, pero estoy asumiendo su apariencia algo como:

int main(){ 
    pid_t pid = fork(); 
    if(pid == 0){ //child process 
     //call some program 
    else //parent process 
     wait(&status); //or waitpid(pid, &status, 0) 
     //continue with the program 
} 

el problema está en la espera() o waitpid(), es ver como si se ejecuta el programa en OS como Ubuntu después de usar Ctrl + Z ¡su hijo está recibiendo el SIGTSTP pero la función wait() en el proceso principal todavía está esperando!

La forma correcta de hacerlo es reemplazar el wait() en el elemento primario con pause() y crear otro controlador que capture SIGCHLD. Por ejemplo:

void sigHandler(int signum){ 
    switch(signum){ 
     case SIGCHLD: 
      // note that the last argument is important for the wait to work 
      waitpid(-1, &status, WNOHANG); 
      break; 
    } 
} 

En este caso después de que el proceso hijo reciben Ctrl + Z el proceso padre también reciben SIGCHLD y la pausa return().

0

Podría llegar tarde para responder la pregunta aquí, pero esto fue lo que funcionó cuando tuve el mismo problema.De acuerdo con las páginas man para tcsetpgrp()

La función tcsetpgrp() hace que el grupo de procesos con ID de grupo de proceso pgrp el grupo primer plano de proceso en el terminal asociado a fd, que debe ser el terminal de control de la el proceso de llamada, y siguen estando asociados con su sesión. Además, pgrp debe ser un grupo de proceso (no vacío) que pertenece a la misma sesión que el proceso de llamada .

Si tcsetpgrp() es llamado por un miembro de un grupo de procesos de fondo en su sesión, y el proceso de llamada no está bloqueando o haciendo caso omiso de SIGTTOU, una señal SIGTTOU se envía a todos los miembros de este grupo de proceso en segundo plano .

Entonces, lo que funcionó para mí fue ignorar la señal SIGTTOU en el programa de shell, antes de crear los procesos que pasarían a primer plano. Si no ignoro esta señal, el kernel enviará esta señal a mi programa de shell y la suspenderá.

Cuestiones relacionadas