wait(2) | System Calls Manual | wait(2) |
wait, waitpid, waitid - wacht op toestand verandering in een proces
Standard C bibliotheek (libc, -lc)
#include <sys/wait.h>
pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *_NULL_baarwstatus, int opties);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int opties);
/* Dit is het glibc en POSIX interface; zie
OPMERKING voor informatie over de ruwe systeem aanroep. */
waitid():
Vanaf glibc 2.26:
_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L
glibc 2.25 en eerder:
_XOPEN_SOURCE
|| /* Vanaf glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
|| /* Glibc <= 2.19: */ _BSD_SOURCE
Al deze systeem aanroepen worden gebruikt om te wachten op een toestandsverandering in een kind van het aanroepende proces en verkrijgen informatie over het kind wiens toestand werd veranderd. Een toestandsverandering wordt gezien als: het kind werd beëindigd; het kind werd beëindigd door een signaal; of het kind werd hervat door een signaal. In het geval van een beëindigd kind, het uitvoeren van een "wacht" maakt het mogelijk dat het systeem de hulpbronnen die geassocieerd zijn met het kind kunnen vrijgeven; als de "wacht" niet wordt uitgevoerd, dan blijft het beëindigde kind een een "zombie" toestand (zie OPMERKINGEN hieronder).
Als een kind al van toestand is veranderd, dan keren deze aanroepen meteen terug. Anders zouden ze blokkeren totdat een kind van toestand verandert of een signaal verwerker interrumpeert de aanroep (aannemende dat systeem aanroepen niet automatisch geherstart worden gebruik makende van de SA_RESTART vlag van sigaction(2)). In de rest van deze pagina:een kind waarvan de toestand werd veranderd en waarop niet gewacht werd door een van de systeem aanroepen wordt aangeduid als waitable.
De wait() systeem aanroep schort het uitvoeren van de huidige thread op totdat een van zijn kinderen eindigt. De aanroep wait(&wstatus) is equivalent aan:
waitpid(-1, &wstatus, 0);
De waitpid() systeem aanroep schort het uitvoeren van de huidige thread op tot dat een kind gespecificeerd door pid argument is veranderd van toestand. Standaard wacht waitpid() alleen op beëindigde kinderen, maar is dit gedrag aanpasbaar via het opties argument, zoals hieronder beschreven.
De waarde van pid kan een van de volgende zijn:
De waarde van opties is een OF (incl.) van nul of meer van de volgende constanten:
(Zie hieronder voor de alleen-Linux opties.)
Als wstatus niet NULL is, dan slaan wait() en waitpid() status informatie op in de int naar welk het wijst. Dit geheel getal kan worden ingezien met de volgende macro´s (die het geheel getal zelf als argument gebruiken, niet de wijzer er naar toe, zoals gedaan in wait() en waitpid()!):
De waitid() systeem aanroep (beschikbaar vanaf Linux 2.6.9.) geeft preciezere controle over het wachten op toestandsveranderingen van kinderen
De idtype en id argumenten selecteren de kind(eren) om op te wachten, als volgt:
De kind status veranderingen om te wachten worden gespecificeerd door OF´en van een of meer van de volgende vlaggen in opties:
De volgende vlaggen mogen additioneel worden geOF´d in opties:
Bij een succesvolle terugkeer, waitid() vult de volgende velden van de siginfo_t structure aangewezen door infop:
Als WNOHANG werd opgegeven in opties en er waren geen kinderen in een wacht toestand, dan geeft waitid() meteen 0 terug and de status van de siginfo_t structure aangewezen door infop hangt af van de implementatie. Om (overdraagbaar) dit geval te onderscheiden van die waar een kind zich in een wacht toestand bevond, maak dan het si_pid veld nul voor de aanroep en controleer op een niet-nul waarde in dit veld nadat de aanroep terugkeerde.
POSIX.1-2008 Technical Corrigendum 1 (2013) voegt de eis toe dat wanneer WNOHANG werd gespecificeerd in opties en er waren geen kinderen wacht toestand, dan zou waitid() de si_pid en si_signo velden nul moeten maken. Op Linux en andere implementaties die aan deze eis voldoen, is het niet noodzakelijk om het si_pid veld nul te maken voor het aanroepen van waitid(). Echter volgen niet alle implementaties de POSIX.1 specificatie op dit punt.
wait(): bij succes, retourneert het proces ID van het beëindigde kind; bij falen wordt een -1 teruggegeven.
waitpid(): bij succes, retourneert het proces ID van het kind waarvan de status werd veranderd; als WNOHANG gebruikt werd en een of meer kind(eren) aangeduid door pid bestaan, maar hebben hun toestand niet verandert, dan wordt nul teruggegeven. Bij een fout wordt -1 teruggegeven.
waitpid(): geeft 0 terug bij succes of als WNOHANG werd opgegeven en geen kind(eren) aangeduid door id is nog niet van toestand veranderd; bij een fout wordt -1 teruggegeven.
Bij falen, zal elk van deze aanroepen errno zetten om de fout aan te duiden.
SVr4, 4.3BSD, POSIX.1-2001.
Een kind dat stopt, maar waar niet op gewacht is wordt een "zombie". De kernel onderhoudt een minimale verzameling van informatie over het zombie proces (PID, beëindiging status, hulpbron gebruik informatie) om de ouder in staat te stellen om later te wachten om de informatie over het kind te verkrijgen. Zolang de zombie niet werd verwijderd door te wachten, zal het een item in de proces tabel van de kernel in beslag nemen, en als deze tabel vol is, is het niet meer mogelijk om meer processen te creëren. Als een ouder proces beëindigd, dan zullen zijn "zombie"kinderen (als die er zijn) worden geadopteerd door init(1), (of door het dichtstbijzijnde "maaimachine" proces zoals gedefinieerd door het gebruik van de prctl(2) PR_SET_CHILD_SUBREAPER operatie); init(1) voert automatisch een wacht uit om zombies te verwijderen.
POSIX.1-2001 specificeert dat als een dispositie van SIGCHLD is gezet op SIG_IGN of de SA_NOCLDWAIT vlag is gezet voor SIGCHLD (zie sigaction(2)), dan zullen kinderen die eindigen geen zombies worden en een aanroep van wait() of waitpid() zal blokkeren totdat alle kinderen beëindigd zijn, en vervolgens falen met errno gezet op ECHILD. (De originele POSIX standaard liet het gedrag van het zetten van SIGCHLD op SIG_IGN ongespecificeerd. Let op dat zelfs als de standaard dispositie van SIGCHLD "negeer" is, dan zal het expliciet zetten van de dispositie op SIG_IGN resulteren in een andere behandeling van zombie proces kinderen.)
Linux 2.6 voldoet aan de POSIX eisen. Hoewel Linux 2.4 (en eerder) dat niet deed: als een wait() of waitpid() aanroep wordt gedaan terwijl SIGCHLD wordt geïgnoreerd, dan gedraagt de aanroep zich alsof SIGCHLD niet geïgnoreerd werd, dat betekend, de aanroep blokkeert totdat het volgende kind stopt en vervolgens het proces ID en de status van dat kind teruggeeft.
In de Linux kernel, een kernel-thread is niet anders van constructie dan een proces. In plaats daarvan, is een thread eenvoudig weg een proces dat werd aangemaakt door de Linux-unieke clone(2) systeem aanroep; andere routines zoals de overdraagbare pthread_create(3) aanroep zijn geïmplementeerd met clone(2). Voor Linux 2,4 was een thread slechts een speciaal geval van een proces, met als consequentie dat een thread niet kon wachten op kinderen of een andere thread, zelfs wanneer de laatste tot dezelfde thread groep behoorde. Echter, schrijft POSIX wel deze functionaliteit voor, en vanaf Linux 2.4 kan een thread, en doet dat ook standaard, wachten op kinderen of andere thread in dezelfde thread groep.
De volgende Linux-specifieke opties zijn alleen van toepassing op kinderen aangemaakt door clone(2); die kunnen ook gebruikt worden, sinds Linux 4.7, met waitid():
Vanaf Linux 4.7, is de __WALL vlag automatisch inbegrepen als het kind wordt ge-"ptraced".
wait() is eigenlijk een bibliotheek functie die (in glibc) is geïmplementeerd als een aanroep naar wait4(2).
Op sommige architecturen, is er geen waitpid() systeem aanroep; in plaats daarvan, is dit interface geïmplementeerd door een C bibliotheek omwikkel functie die wait4(2) aanroept.
De ruwe waitid() systeem aanroep gebruikt het vijfde argument, van het type struct rusagefP. Als dit argument niet-NULL is, dan wordt het gebruikt om hulpbron informatie over het kind te retourneren, op dezelfde manier als wait4(2). Zie getrusage(2) voor details.
Volgens POSIX.1-2008 moet een applicatie die waitid() aanroept er voor zorgen dat infop wijst naar een siginfo_t structure (m.a.w. dat het een niet-null wijzer is). Op Linux, als infop gelijk is aan NULL, dan is waitid() succesvol en retourneert het proces ID van het kind waarop gewacht wordt. Applicaties moeten vermijden op dit inconsistent, niet-standaard en onnodige kenmerk te vertrouwen.
Het volgende programma demonstreert het gebruik van fork(2) en waitpid(). Het programma creëert een kind proces. Als geen commando regel argument mee gegeven werd naar het programma, dan schort het kind zijn uitvoer op door pause(2) te gebruiken, om zo toe te staan dat de gebruiker signalen naar het kind kan sturen. Anders, als wel een commando regel argument werd mee gegeven, dan stop het kind onmiddellijk, en gebruikt het gehele getal mee gegeven op de commando regel als de uitvoer status. Het ouder proces voert een lus uit die het kind door gebruik van waitpid() monitort, en gebruikt de W*() macros, zoals hierboven beschreven, om de wacht status waarde te analyseren.
De volgend shell sessie demonstreert het gebruik van het 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 $
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> int main(int argc, char *argv[]) {
int wstatus;
pid_t cpid, w;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code uitgevoerd door kind */
printf("Child PID is %jd\n", (intmax_t) getpid());
if (argc == 1)
pause(); /* Wacht op signalen */
_exit(atoi(argv[1])); ` } else { /* Code uitgevoerd door ouder */
do {
w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(wstatus)) {
printf("exited, status=%d\n", WEXITSTATUS(wstatus));
} else if (WIFSIGNALED(wstatus)) {
printf("killed by signal %d\n", WTERMSIG(wstatus));
} else if (WIFSTOPPED(wstatus)) {
printf("stopped by signal %d\n", WSTOPSIG(wstatus));
} else if (WIFCONTINUED(wstatus)) {
printf("continued\n");
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
exit(EXIT_SUCCESS);
} }
_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2), wait4(2), pthread_create(3), core(5), credentials(7), signal(7)
De Nederlandse vertaling van deze handleiding is geschreven door Jos Boersema <joshb@xs4all.nl>, Mario Blättermann <mario.blaettermann@gmail.com> en Luc Castermans <luc.castermans@gmail.com>
Deze vertaling is vrije documentatie; lees de GNU General Public License Version 3 of later over de Copyright-voorwaarden. Er is geen AANSPRAKELIJKHEID.
Indien U fouten in de vertaling van deze handleiding zou vinden, stuur een e-mail naar debian-l10n-dutch@lists.debian.org.
5 februari 2023 | Linux man-pagina's 6.03 |