2012-10-01 14 views
6

Sto codificando una shell di base in C e sto lavorando per sospendere un processo figlio in questo momento.Dopo aver sospeso il processo figlio con SIGTSTP, la shell non risponde

Penso che il mio gestore di segnale sia corretto e che il processo figlio sia sospeso, ma dopo, il terminale dovrebbe tornare al processo genitore e ciò non sta accadendo.

Il figlio è sospeso, ma la mia shell non registra più alcun input o output. tcsetpgrp() non sembra essere d'aiuto.

Ecco il mio gestore di segnale nel mio codice di shell per 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); 
} 

Qualcuno può dirmi che cosa sto facendo male?

Sto sospendendo il mio guscio insieme al bambino, e devo in qualche modo restituire stdin e stdout alla shell? Come lo farei?

Grazie!

risposta

0

tcsetpgrp indica quale è il lavoro in primo piano. Quando la shell genera un lavoro in primo piano (senza &), dovrebbe creare un nuovo gruppo di processi e renderlo quello in primo piano (del terminale di controllo, non di quello su STDIN). Quindi, premendo CTRL-Z, quel lavoro otterrà il TSTP. È il terminale che sospende il lavoro, non la tua shell. La tua shell non dovrebbe intercettare TSTP o inviare TSTP a nessuno.

Dovrebbe essere solo wait() per il lavoro che ha generato e rilevare quando è stato arrestato (e richiedere il gruppo in primo piano e contrassegnare il lavoro come sospeso internamente). Il comando fg renderebbe il lavoro di pgid nuovamente il gruppo processo in primo piano e inviare un SIGCONT ad esso e aspettare di nuovo, mentre bg sarebbe solo inviare il SIGCONT

+1

Grazie per la risposta. Ho provato a fare quello che dici, ma quando togli il mio gestore di segnale il terminale sospende il genitore e torna a bash. Ho bisogno che il genitore continui a correre. – user1710304

+1

Questo è semplicemente sbagliato, non catturare SIGTSTP causerebbe certamente la sospensione della shell e lascerà andare i processi figli. Ha bisogno di prenderlo così il suo guscio non sospenderà. Sto affrontando lo stesso problema in questo momento ha affrontato in precedenza – Fingolfin

+1

@AdelQodmani, solo il gruppo di processi in foreground del terminale riceve un SIGTSTP quando si preme Ctrl-Z. La shell che attende solo la conclusione del processo avviato, si trova in un gruppo di processi che non è il gruppo di processi in primo piano del terminale. puoi _ignore_ SIGTSTP se vuoi, è probabile ciò che fa la maggior parte delle shell. Il punto è che è necessario giocare con il gruppo di processi in primo piano del terminale. –

2

Si tratta di una vecchia questione, ma ancora penso che ho trovato una risposta.
Lei non ha scritto il codice del vostro genitore, ma io sto assumendo il suo aspetto qualcosa di simile:

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 
} 

il problema è con l'attesa() o waitpid(), è simile se si esegue il programma su OS come Ubuntu dopo aver usato Ctrl + Z il processo figlio sta ricevendo SIGTSTP ma la funzione wait() nel processo padre è ancora in attesa!

Il modo corretto per farlo è sostituire l'attesa() nel parent con pause() e creare un altro gestore che cattura SIGCHLD. Per esempio:

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

In questo caso, dopo il processo figlio ricevono Ctrl +Z il processo padre riceve anche SIGCHLD e il ritorno di pausa().

0

Potrei essere in ritardo per rispondere alla domanda qui, ma questo è ciò che ha funzionato quando ero bloccato con lo stesso problema.Secondo le pagine man per tcsetpgrp()

La funzione tcsetpgrp() rende il gruppo di processo con ID gruppo processo pgrp il primo piano gruppo processo sul terminale associato a fd, che deve essere il terminale di controllo del processo di chiamata e essere ancora associati alla sua sessione. Inoltre, pgrp deve essere un gruppo di processi (non vuoto) appartenente alla stessa sessione del processo di chiamata .

Se tcsetpgrp() viene chiamato da un membro di un gruppo di processo in background in sua sessione, e il processo chiamante non stia bloccando o ignorare SIGTTOU, un segnale SIGTTOU viene inviato a tutti i membri di questo gruppo processo in background .

Quindi, ciò che ha funzionato per me è stato ignorare il segnale SIGTTOU nel programma di shell, prima che avessi creato i processi che sarebbero arrivati ​​in primo piano. Se non ignoro questo segnale, il kernel invierà questo segnale al mio programma shell e lo sospenderà.

Problemi correlati