2012-11-20 18 views
6

ho bisogno di essere in grado di:Linux, waitpid, WNOHANG e zombie

  1. fork di un processo e renderlo execvp (che ho fatto)
  2. di controllo se l'execvp processo figlio ha avuto successo (non sapere come)
  3. di controllo se il processo figlio terminato (che hanno problemi)

sto biforcano un processo e non ho alcun modo per verificare se i execvp del bambino ha lavorato o meno. Se ha fallito, devo essere in grado di sapere che ha fallito. Attualmente sto usando

-1 != waitpid(pid, &status, WNOHANG) 

Ma sembra che se l'execv del processo pid fallisce il waitpid non restituisce -1.

Come posso verificarlo? Ho letto la pagina man waitpid, ma non è chiaro per me; forse il mio inglese non è abbastanza buono.

MODIFICA: per ulteriori informazioni:
Sto costruendo il mio terminale per un lavoro a domicilio. Ho bisogno di ottenere come input una stringa di comando, diciamo "ls" e quindi devo eseguire il comando.
Dopo il child fork, il figlio richiama execvp per eseguire il comando (dopo aver analizzato la stringa) e il genitore deve verificare se c'è un '&' alla fine del comando o meno.
se il segno "&" non esiste alla fine del comando, il genitore deve attendere l'esecuzione del figlio.

quindi ho bisogno di sapere se il execvp non è riuscito. Se non ha fallito, il genitore usa waitpid per aspettare che il bambino finisca l'esecuzione. Se fallisce, il genitore non aspetterà il bambino.

+7

titolo di domanda migliore di sempre. – valentinas

+1

Ci sono un paio di fattori che potrebbero influenzare la tua soluzione qui: in cosa stai eseguendo il tuo processo? Hai la possibilità di modificare _that_? Va bene non sapere se l'execvp ha avuto esito negativo fino a quando il bambino non è uscito? Se pubblichi una dichiarazione del problema più dettagliata, potremmo essere in grado di dare un consiglio migliore. – FrankieTheKneeMan

+1

Non puoi inviare un segnale dal bambino al genitore in caso di detto fallimento? –

risposta

4

Una soluzione comune a # 2 è aprire una pipe prima di fork(), quindi scrivere nel figlio dopo l'exec. Nel genitore, una lettura di successo significa che l'exec fallisce; una lettura senza successo significa che l'exec è riuscita e la scrittura non ha mai avuto luogo.

// ignoring all errors except from execvp... 
int execpipe[2]; 
pipe(execpipe); 
fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC); 
if(fork() == 0) 
{ 
    close(execpipe[0]); 
    execvp(...); // on success, never returns 
    write(execpipe[1], &errno, sizeof(errno)); 
    // doesn't matter what you exit with 
    _exit(0); 
} 
else 
{ 
    close(execpipe[1]); 
    int childErrno; 
    if(read(execpipe[0], &childErrno, sizeof(childErrno)) == sizeof(childErrno)) 
    { 
     // exec failed, now we have the child's errno value 
     // e.g. ENOENT 
    } 
} 

In questo modo il genitore senza ambiguità sapere se l'exec ha avuto successo, e come sottoprodotto quale sia il valore errno era in caso di insuccesso.

Se l'esecuzione è stata eseguita correttamente, il processo figlio potrebbe non riuscire ancora con un codice di uscita e l'esame dello stato con la macro WEXITSTATUS fornisce anche tale condizione.

NOTA: la chiamata di waitpid con il flag WNOHANG non è bloccante e potrebbe essere necessario eseguire il polling del processo finché non viene restituito un pid valido.

+0

@ Ryan-Callhoun, grazie, ma la lettura bloccherà il genitore, vero? se l'execvp ha successo ho bisogno che il genitore non aspetti. Ho modificato il mio post per chiarire. grazie! – m1o2

+3

@ m1o2: notare 'FD_CLOEXEC'. La pipe viene chiusa sul child quando 'execv *' riesce. Una lettura restituirà 0 per EOF. – ninjalj

+0

@ninjalj thank you – m1o2

4

Una chiamata exec non deve restituire affatto se riesce, perché sostituisce l'immagine di processo attuale con un altro, per cui se si vuole dire è verificato un errore:

execvp(...); 
/* exec failed and you should exit the 
    child process here with an error */ 
exit(errno); 

lasciare che il genitore processo di sapere se exec falliti si dovrebbe leggere lo stato del processo figlio:

waitpid(pid, &status, WNOHANG); 

E poi utilizzare la macro WEXITSTATUS(status), dalla pagina man:

WEXITSTATUS (stato) restituisce lo stato di uscita del bambino. Questo costituito dalle 8 bit meno significativi dell'argomento stato che il bambino specificato in una chiamata per uscire (3) o _exit (2) o come argomento un'istruzione ritorno in main()

Nota l'ultima istruzione significa che se exec ha esito positivo e viene eseguito il comando si otterrà lo stato di uscita della funzione main() di tale comando, ovvero non è possibile indicare in modo affidabile la differenza tra un errore exec e un comando non riuscito in questo modo , quindi dipende se questo è importante per te.

Un altro problema:

se il segno '&' non esiste alla fine del comando, allora il genitore necessità di attendere il bambino da eseguire.

è necessario chiamare wait() sul processo figlio ad un certo punto del programma, a prescindere dal & per evitare di lasciare il processo figlio in un zombi stato,

Nota: Quando si utilizza il WNOHANG significa che waitpid() restituirà immediatamente se nessun processo ha cambiato il suo stato, cioè non bloccherà, presumo tu lo sappia, altrimenti usa wait() o chiama waitpid() come parte del tuo ciclo principale.

+0

Penso che la parte difficile di questo problema è che il processo _parent_ sa che execvp non è riuscito. – FrankieTheKneeMan

+0

@FrankieTheKneeMan aggiornato – iabdalkader

+0

Dal momento che OP non è in giro per chiarire, giocherò l'avvocato del diavolo: cosa succede se ho bisogno di assicurarmi che il bambino abbia correttamente eseguito execvp'ed prima di inviare segnali o altre informazioni di controllo, e quindi non può aspettare che esca effettivamente? – FrankieTheKneeMan