Scroll to navigation

WAIT(2) Linux Programmeurs Handleiding WAIT(2)

NAAM

wait, waitpid, waitid - wacht op toestand verandering in een proces

SAMENVATTING

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);

pid_t waitpid(pid_t pid, int *wstatus, 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. */

Test Macro´s in glibc (zie feature_test_macros(7)):

waitid():

Sinds glibc 2.26: _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L
Glibc 2.25 en eerder: _XOPEN_SOURCE || /* Sinds glibc 2.12: */ _POSIX_C_SOURCE >= 200809L || /* Glibc versies <= 2.19: */ _BSD_SOURCE

BESCHRIJVING

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.

wait() and waitpid()

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:

< -1
wat betekend dat er gewacht wordt op elk kind proces van wie de proces groep ID gelijk is aan de absolute waarde van pid.
-1
wat betekent wacht op een kind proces.
0
wat betekend dat er gewacht wordt op elk kind proces van wie het proces groep ID gelijk is aan dat van het aanroepende proces ten tijde van de aanroep van waitpid().
> 0
wat betekend dat er gewacht wordt op elk kind van wie het proces ID gelijk is aan de waarde van pid.

De waarde van opties is een OF (incl.) van nul of meer van de volgende constanten:

WNOHANG
betekend dat er onmiddellijk wordt teruggekeerd als geen kind beëindigd was.
WUNTRACED
keer ook terug als het kind werd beëindigd (maar niet getraceerd via ptrace(2)). In de status van traced kinderen die werden beëindigd wordt voorzien, zelfs als deze optie niet werd opgegeven.
WCONTINUED (sinds Linux 2.6.10)
keer ook terug als een beëindigd kind werd hervat door het afleveren van SIGCONT.

(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()!):

WIFEXITED(wstatus)
retourneert "waar" als het kind normaal beëindigde, dat is, door het aanroepen van exit(3) of _exit(2), of door terug te keren uit main().
WEXITSTATUS(wstatus)
retourneert de terugkeer status van het kind. Deze bestaat uit de minst belangrijke 8 bits van het status argument dat het kind specificeerde in een aanroep van exit(3) of _exit(2) of als het argument van een return statement in main(). Deze macro moet alleen gebruikt worden als WIFEXITED een "waar" terug gaf.
WIFSIGNALED(wstatus)
geeft "waar" terug als het proces eindigde door een signaal.
WTERMSIG(wstatus)
geeft het nummer van het signaal dat ervoor zorgde dat het kind proces eindigde. Deze macro kan alleen gebruikt worden als WIFSIGNALED "waar" terug gaf.
WCOREDUMP(wstatus)
retourneert "waar" als het kind een core dump produceerde (zie core(5)). Deze macro kan alleen gebruikt worden als WIFSIGNALED "waar" terug gaf.
Deze macro is niet gespecificeerd in POSIX.1-2001 en is niet beschikbaar in enkele UNIX implementaties (b.v. AIX, SunOS). Daarom, sluit zijn gebruik binnen #ifdef WCOREDUMP ... #endif in.
WIFSTOPPED(wstatus)
geeft "waar" terug als het kind proces werd beëindigd door het afleveren van een signaal; dit is alleen mogelijk als de aanroep werd gedaan met WUNTRACED of wanneer het kinderen wordt getraceerd (zie ptrace(2)).
WSTOPSIG(wstatus)
geeft het nummer van het signaal dat ervoor zorgde dat het kind stopte. Deze macro kan alleen afgehandeld worden als WIFSTOPPED ongelijk-nul teruggaf.
WIFCONTINUED(wstatus)
(vanaf Linux 2.6.10) geeft "waar" terug als het kind werd hervat door het aanleveren van SIGCONT.

waitid()

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:

idtype == P_PID
Wacht op het kind wiens proces ID overeenkomt met id.
idtype == P_PID (vanaf Linux 5.4)
Wacht op het kind gerefereerd door de PID bestands beschrijving gespecificeerd in id. (Zie pidfd_open(2) voor verdere informatie over PID bestands beschrijvers.)
idtype == P_PGID
Wacht op enig kind wiens proces groep ID overeenkomt met id. Vanaf Linux 5.4, als id is NUL, dan wacht op enig kind dat tot dezelfde proces groep zit als de proces groep van de aanroeper ten tijde van de aanroep.
idtype == P_ALL
Wacht op enig kind; id wordt geïgnoreerd.

De kind status veranderingen om te wachten worden gespecificeerd door OF´en van een of meer van de volgende vlaggen in opties:

WEXITED
Wacht op kinderen die zijn beëindigd.
WSTOPPED
Wacht op kinderen die zijn gestopt door het leveren van een signaal.
WCONTINUED
Wacht op (eerder gestopte) kinderen die zijn hervat door het aanleveren van SIGCONT.

De volgende vlaggen mogen additioneel worden geOF´d in opties:

WNOHANG
Zoals voor waitpid().
WNOWAIT
Laat het kind in een wachtbare status; een latere "wait"-aanroep kan opnieuw gebruikt worden om de status van het kind op te vragen.

Bij een succesvolle terugkeer, waitid() vult de volgende velden van de siginfo_t structure aangewezen door infop:

si_pid
Het proces ID van het kind.
si_uid
Het effectieve gebruiker ID van het kind. (Dit veld is niet gezet op de meeste andere implementaties.)
si_signo
Altijd gezet op SIGCHLD.
si_status
Ofwel de retour status van het kind, zoals mee gegeven aan _exit(2) (of exit(3)), ofwel het signaal de veroorzaakte het kind te beëindigen, stoppen of doorgaan. Het si_code veld kan worden gebruikt om te bepalen hoe dit veld te interpreteren.
si_code
Zet op een van: CLD_EXITED (kind roep aan _exit(2)); CLD_KILLED (kind beëindigd door signaal); CLD_DUMPED (kind beëindigd door signaal, en dumpte core); CLD_STOPPED (kind gestopt door signaal); CLD_TRAPPED (getraceerd kind zit vast); or CLD_CONTINUED (kind vervolgt door SIGCONT).

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.

EIND WAARDE

wait(): bij succes, geeft het proces ID van het beëindigde kind terug; bij falen wordt een -1 geretourneerd.

waitpid(): bij succes, retourneert het proces ID van het kind waarvan de status werd veranderd; als WHOHANG werd opgegeven en een of meer kind(eren) gegeven door pid bestaan, maar hebben nog geen status verandert, dan wordt 0 teruggegeven. Bij een fout wordt -1 teruggegeven.

waitid(): retourneert 0 bij succes of als WNOHANG werd opgegeven en geen kind(eren) gespecificeerd door id heeft zijn status nog niet veranderd; bij een fout wordt -1 teruggegeven.

Elk van deze aanroepen set errno op een van toepassing zijnde waarde in het geval van een fout.

FOUTEN

ECHILD
(voor wait()) Het aanroepende proces heeft geen enkel kind waarop gewacht wordt.
ECHILD
(voor waitpid() of waitid()) Het proces gespecificeerd door pid (waitpid()) of idtype en id (waitid()) bestaat niet of is geen kind van het aanroepende proces. (Dit kan gebeuren als het eigen kind als de actie voor SIGCHLD is gezet op SIG_IGN. Zie ook de Linux Opmerkingen sectie over threads.)
EINTR
WNOHANG was is niet gezet en een gedeblokkeerd signaal of een SIGCHLD werd ontvangen; zie signal(7).
EINVAL
Het opties argument was ongeldig.

VOLDOET AAN

SVr4, 4.3BSD, POSIX.1-2001.

OPMERKINGEN

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.

Linux notities

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():

__WCLONE
Wacht alleen op "kloon" kinderen. Als weggelaten, wacht dan alleen op "niet-kloon" kinderen. (Een "kloon"kind is er een dat geen signaal levert, of een signaal anders dan SIGCHLD aan zijn ouder bij beëindiging.) Deze optie wordt genegeerd als _WALL ook werd gespecificeerd.
__WALL (sinds Linux 2.4)
Wacht op alle kinderen, van welk type ("kloon" of "niet-kloon") dan ook.
__WNOTHREAD (sinds Linux 2.4)
Wacht niet op kinderen of andere threads in dezelfde thread groep. Dit was standaard voor Linux 2.4.

Vanaf Linux 4.7, is de __WALL vlag automatisch inbegrepen als het kind wordt ge-"ptraced".

C library/kernel verschillen

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.

BUGS

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.

VOORBEELDEN

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
$


Programma bron

#include <sys/wait.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
    pid_t cpid, w;
    int wstatus;
    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);
    }
}

ZIE OOK

_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)

COLOFON

Deze pagina is onderdeel van release 5.10 van het Linux man-pages-project. Een beschrijving van het project, informatie over het melden van bugs en de nieuwste versie van deze pagina zijn op https://www.kernel.org/doc/man-pages/ te vinden.

VERTALING

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.

1 november 2020 Linux