NOME
wait, waitpid, waitid − aspetta che il processo cambi stato
SINTASSI
#include
<sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int opzioni);
int
waitid(idtype_t idtype, id_t id,
siginfo_t *infop, int
opzioni);
/* This is the glibc and POSIX interface; see
NOTES for information on the raw system call. */
Macro per test di funzionalità per glibc (vedere feature_test_macros(7)):
waitid():
_SVID_SOURCE ||
_XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */
_POSIX_C_SOURCE >= 200809L
DESCRIZIONE
Tutte queste chiamate di sistema si usano per attendere cambiamenti di stato in un figlio del processo chiamante, e ottenere informazioni sul figlio il cui stato è cambiato. Un cambiamento di stato avviene quando: il processo figlio è terminato; il figlio è stato arrestato da un segnale; il figlio è stato ripristinato da un segnale. In caso di un figlio terminato, un’attesa permette al sistema di rilasciare le risorse associate al figlio; se non viene eseguita un’attesa, allora il figlio terminato rimane in uno stato "zombie" (vedere le NOTE sotto).
Se un figlio ha già cambiato stato, allora le chiamate tornano immediatamente. Altrimenti esse si bloccano fino a quando un figlio cambia stato o un gestore di segnale interrompe la chiamata (supponendo che le chiamate di sistema non siano automaticamente riavviate usando il flag SA_RESTART di sigaction(2)). Nel resto di questa pagina un figlio il cui stato è cambiato, e che nessuna di queste chiamate di sistema ha aspettato, è definito aspettabile.
wait() e
waitpid()
La chiamata di sistema wait() sospende
l’esecuzione del processo chiamante fino a quando uno
dei suoi figli termina. La chiamata wait(&status)
è equivalente a:
waitpid(−1, &status, 0);
La chiamata di sistema waitpid() sospende l’esecuzione del processo chiamante fino a quando un figlio specificato dall’argomento pid ha cambiato stato. Il comportamento predefinito di waitpid() è attendere solo i figli terminati, ma questo comportamento è modificabile attraverso l’argomento opzioni come descritto di seguito.
Il valore di pid può essere:
< −1 |
che significa attesa di qualunque processo figlio il cui gruppo ID del processo sia uguale al valore assoluto di pid. | ||
−1 |
che significa aspettare qualunque processo figlio. | ||
0 |
che significa aspettare qualunque processo figlio il cui gruppo ID del processo sia uguale a quello del processo chiamante. | ||
> 0 |
che significa aspettare il figlio il cui ID di processo sia uguale al valore di pid. |
Il valore di opzioni è un OR di zero o più delle seguenti costanti:
WNOHANG |
torna immediatamente se nessun figlio è uscito. | ||
WUNTRACED |
torna anche se un figlio si è arrestato (ma non tracciato attraverso ptrace(2)). Lo stato del figlio non tracciato che è stato arrestato è fornito anche se l’opzione non è specificata. |
WCONTINUED (A partire da Linux 2.6.10)
torna anche se un figlio arrestato è stato riesumato inviando SIGCONT.
(Per le opzioni solo Linux vedere oltre).
Se
status non è NULL , wait() e
waitpid() memorizzano l’informazione di stato
in int a cui punta. Questo intero può essere
verificato con le seguenti macro (che prendono lo stesso
intero come argomento, non come un puntatore ad esso, come
fanno wait() e waitpid()!):
WIFEXITED(stato)
restituisce true se il figlio è terminato normalmente, ovvero, chiamando exit(3) o _exit(2), o tornando da main().
WEXITSTATUS(stato)
ritorna lo stato di uscita del figlio. Esso consiste negli 8 bit meno significativi dell’argomento status che il figlio ha specificato in una chiamata a exit(3) o _exit(2) o come argomento per una dichiarazione di ritorno in main(). Questa macro deve essere impiegata solo se WIFEXITED restituisce true.
WIFSIGNALED(stato)
restituisce true se il processo figlio è stato terminato da un segnale.
WTERMSIG(stato)
restituisce il numero del segnale che ha causato l’arresto del processo figlio. Questa macro deve essere impiegata solo se WIFSIGNALED ha restituito true.
WCOREDUMP(stato)
restituisce true se il figlio ha prodotto un core dump. Questa macro deve essere impiegata solo se WIFSIGNALED ha restituito true. Questa macro non è specificata in POSIX.1-2001 e non è disponibile in alcune implementazioni Unix (per esempio AIX, SunOS). Usarla solo racchiusa tra #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(stato)
restituisce true se il processo figlio è stato arrestato inviando un segnale; questo è possibile solo se la chiamata è stata effettuata usando WUNTRACED o quando il figlio è stato tracciato (vedere ptrace(2)).
WSTOPSIG(stato)
restituisce il numero del segnale che ha causato l’arresto del processo figlio. Questa macro deve essere impiegata solo se WIFSTOPPED ha restituito true.
WIFCONTINUED(stato)
(A partire da Linux 2.6.10) restituisce true se il processo figlio è stato riesumato inviando SIGCONT.
waitid()
La chiamata di sistema waitid() (disponibile a
partire da Linux 2.6.9) fornisce un controllo più
preciso su quale cambiamento di stato del processo figlio
aspettare.
Gli argomenti
idtype e id selezionano il figlio(i) da
aspettare, come segue:
idtype == P_PID
Aspetta il figlio il cui ID di processo corrisponde a id.
idtype == P_PGID
Aspetta qualunque figlio il cui ID di gruppo del processo corrisponda a id.
idtype == P_ALL
Aspetta qualunque processo figlio; id è ignorato.
Il cambiamento di stato del processo figlio da aspettare è specificato eseguendo un OR su uno o più dei seguenti flag in opzioni:
WEXITED |
Aspetta il figlio che è terminato. | ||
WSTOPPED |
Aspetta il figlio che è stato arrestato con l’invio di un segnale. | ||
WCONTINUED |
Aspetta i figli (precedentemente arrestati) che sono stati riesumati inviando SIGCONT. |
Si può inoltre eseguire un OR sui seguenti flag in opzioni:
WNOHANG |
Come per waitpid(). | ||
WNOWAIT |
Lascia il figlio in uno stato in attesa; una successiva chiamata di attesa può essere usata per trovare di nuovo l’informazione sullo stato del figlio. |
In seguito a un ritorno con successo, waitid() riempie i seguenti campi della struttura siginfo_t a cui punta infop:
si_pid |
L’ID di processo del figlio. | ||
si_uid |
L’ID reale dell’utente del figlio. (Questo campo non viene impostato nella maggior parte delle altre implementazioni.) | ||
si_signo |
Imposta sempre a SIGCHLD. | ||
si_status |
O lo stato di uscita del figlio, come dato a _exit(2) (o exit(3)), o il segnale che ha causato la terminazione, l’arresto o la continuazione del figlio. Il campo si_code può essere usato per determinare come interpretare questo campo. | ||
si_code |
Imposta a uno tra: CLD_EXITED (figlio chiamato _exit(2)); CLD_KILLED (figlio terminato da un segnale); CLD_DUMPED (figlio terminato da un segnale, ed eseguito un core dump); CLD_STOPPED (figlio arrestato da un segnale); CLD_TRAPPED (il figlio tracciato è stato bloccato); o CLD_CONTINUED (figlio continuato da SIGCONT). |
Se WNOHANG è stato specificato in opzioni e non c’erano figli in uno stato di attesa, allora waitid() restituisce immediatamente 0, e lo stato della struttura siginfo_t a cui punta infop non è specificato. Per distinguere questo caso da quello in cui un figlio era in uno stato di attesa, il campo si_pid viene impostato a zero prima della chiamata e, dopo il ritorno della chiamata, verifica che in questo campo non ci sia un valore zero.
VALORI RESTITUITI
wait(): in caso di successo, restituisce l’ID del processo del figlio terminato; in caso di errore restituisce −1.
waitpid(): in caso di successo, restituisce l’ID del processo del figlio il cui stato è cambiato; se WNOHANG era specificato e uno o più figli specificati da pid esiste, ma non ha ancora cambiato stato, allora viene restituito 0. In caso di errore restituisce −1. waitid(): restituisce 0 in caso di successo o se WNOHANG era specificato e nessun figlio(i) specificato da id ha ancora cambiato stato; in caso di errore restituisce −1. Ciascuna di queste chiamate imposta errno ad un valore appropriato in caso di errore.
ERRORI
ECHILD |
(per wait()) Il processo chiamante non ha nessun figlio inaspettato. | ||
ECHILD |
(per waitpid() o waitid()) Il processo specificato da pid (waitpid()) o idtype e id (waitid()) non esiste o non è un figlio del processo chiamante (ciò può accadere per il figlio di un processo se l’azione per SIGCHLD è impostata a SIG_IGN. Vedere anche la sezione Note Linux sui thread). | ||
EINTR |
WNOHANG non era impostata ed è stato intercettato un segnale sbloccato o un SIGCHLD; vedere signal(7). | ||
EINVAL |
Gli argomenti delle opzioni non erano validi. |
CONFORME A
SVr4, 4.3BSD, POSIX.1-2001.
NOTE
Un figlio che termina, ma in modo inaspettato, diviene uno "zombie". Il kernel mantiene un insieme minimo di informazioni sui processi zombie (PID, stato di terminazione, informazioni sull’uso delle risorse) allo scopo di permettere al padre di eseguire in seguito un wait per ottenere informazioni sul figlio. Se uno zombie non viene rimosso dal sistema attraverso un wait, esso consumerà uno slot nella tabella dei processi del kernel, e se questa tabella si riempie, non sarà possibile creare ulteriori processi. Se un processo padre termina, allora i suoi figli "zombie" (se ce ne sono) sono adottati da init(8), che automaticamente esegue un wait per rimuovere gli zombie.
POSIX.1-2001 specifica che se la disposizione di SIGCHLD è impostata a SIG_IGN o il flag SA_NOCLDWAIT è impostato per SIGCHLD (vedere sigaction(2)), i figli terminati non diventano zombie e una chiamata a wait() o waitpid() verrà bloccata fino a quando tutti i figli sono terminati, e in seguito fallisce con errno impostato a ECHILD. (Lo standard POSIX originale lasciava il comportamento di impostare SIGCHLD a SIG_IGN non specificato. Si noti che, anche se la disposizione predefinita di SIGCHLD è "ignore", impostarla esplicitamente a SIG_IGN comporterà un diverso trattamento dei processi figlio zombie). Linux 2.6 è conforme a questa specifica. Tuttavia Linux 2.4 (e precedenti) non lo è: se una chiamata wait() o waitpid() è effettuata mentre SIGCHLD è ignorato, la chiamata si comporta come se SIGCHLD non fosse stato ignorato, ovvero, la chiamata si blocca fino a quando il prossimo figlio termina e quindi restituisce l’ID del processo e lo stato di questo figlio.
Note
Linux
Nel kernel Linux un thread programmato dal kernel non
è un costrutto distinto da un processo. Invece un
thread è semplicemente un processo creato usando la
chiamata esclusiva di Linux clone(2); altre routine
come la chiamata portabile pthread_create(3) sono
implementate usando clone(2). Prima di Linux 2.4 un
thread era solo un caso speciale di un processo, e come
conseguenza un thread non poteva aspettare il figlio di un
altro thread, anche se l’ultimo apparteneva allo
stesso gruppo del thread. Tuttavia POSIX prescrive tale
funzionalità, e a partire da Linux 2.4 un thread
può, e in modo predefinito lo fa, aspettare il figlio
di un altro thread nello stesso gruppo del thread.i
Le seguenti
opzioni specifiche di Linux devono essere usate con i
figli creati usando clone(2); esse non possono essere
usate con waitid():
__WCLONE
Aspetta solo i figli di "clone". Se omessa allora aspetta solo i figli "non-clone". (Un figlio "clone" è uno che non invia segnali, o un segnale diverso da SIGCHLD ai suoi genitori quando viene terminato). Questa opzione è ignorata se viene anche specificato __WALL.
__WALL (a partire da Linux 2.4)
Aspetta tutti i figli, qualunque sia il loro tipo ("clone" o "non−clone").
__WNOTHREAD (a partire da Linux 2.4)
Non aspetta figli di altri thread nello stesso gruppo del thread. Questo era il comportamento predefinito prima di Linux 2.4.
Differenze
tra le ABI della libreria C e quelle del kernel
La chiamata di sistema diretta waitid() accetta un
quinto argomento, di tipo struct rusage *. Se
questo argomento non è NULL, viene usato per
restituire informazioni sull’uso delle risorse del
figlio, allo stesso modo di wait4(2). Vedere
getrusage(2) per i dettagli.
BUG
Secondo POSIX.1-2008, un’applicazione che chiama waitid() deve assicurarsi che infop punti ala struttura siginfo_t (cioé, che sia un puntatore non-NULL). Su Linux, se infop è NULL, waitid() va a buon fine, e ritorna l’ID di processo del figlio aspettato. Le applicazioni dovrebbero evitare di contare su questa caratteristica non conforme, non standard e non necessaria.
ESEMPIO
Il seguente programma dimostra l’uso di fork(2) e waitpid(). Il programma crea un processo figlio. Se dalla linea di comando non viene fornito alcun argomento al programma, allora il figlio sospende la propria esecuzione usando pause(2), per permettere all’utente di mandare il segnale al figlio. Altrimenti, se viene fornito un argomento dalla linea di comando, allora il figlio esce immediatamente, usando l’intero fornito dalla linea di comando come stato di uscita. Il processo genitore esegue un ciclo che controlla il figlio usando waitpid(), e usa le macro W*() descritte sopra per analizzare il valore dello stato di attesa.
La seguente sessione di shell dimostra l’uso del programma:
$ ./a.out
&
Child PID is 32360
[1] 32359
$ kill −STOP 32360
stopped by signal 19
$ kill −CONT 32360
continued
$ kill −TERM 32360
killed by signal 15
[1]+ Done ./a.out
$
Sorgente del
programma
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == −1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{ /* Codice eseguito dal figlio */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Aspetta i segnali */
_exit(atoi(argv[1]));
} else { /*
codice eseguito dal genitore */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == −1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if
(WIFEXITED(status)) {
printf("exited, status=%d\n",
WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n",
WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) &&
!WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
VEDERE ANCHE
_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2), wait4(2), pthread_create(3), credentials(7), signal(7)
COLOPHON
Questa pagina fa parte del rilascio 3.73 del progetto Linux man-pages. Una descrizione del progetto, le istruzioni per la segnalazione degli errori, e l’ultima versione di questa pagina si trova su http://www.kernel.org/doc/man−pages/.
La versione
italiana fa parte del pacchetto man-pages-it v. 3.73,
a cura di: ILDP "Italian Linux Documentation
Project" http://www.pluto.it/ildp
Per la traduzione in italiano si può fare riferimento
a http://www.pluto.it/ildp/collaborare/
Segnalare eventuali errori di traduzione a
ildp [AT] pluto.it