Provided by: manpages-pl-dev_4.26.0-1_all 

NAZWA
wait, waitpid, waitid - oczekuje na zmianę stanu procesu
BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)
SKŁADNIA
#include <sys/wait.h>
pid_t wait(int *_Nullable wstatus);
pid_t waitpid(pid_t pid, int *_Nullable wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
/* Jest to interfejs glibc i POSIX; zob. UWAGI, aby
uzyskać informacje o surowym wywołaniu systemowym. */
Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):
waitid():
Od glibc 2.26:
_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L
glibc 2.25 i wcześniejsze:
_XOPEN_SOURCE
|| /* Od glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
|| /* glibc <= 2.19: */ _BSD_SOURCE
OPIS
Wszystkie te wywołania systemowe służą do oczekiwania na zmianę statusu potomka procesu wywołującego oraz
do uzyskania informacji o potomku, którego stan uległ zmianie. Za zmianę stanu uważa się: zakończenie
potomka, zatrzymanie potomka przez sygnał, wznowienie potomka przez sygnał. W przypadku zakończonego
potomka, wykonanie oczekiwania pozwala systemowi na zwolnienie zasobów związanych z potomkiem; gdyby
oczekiwanie nie zostało wykonane, to potomek pozostałby w stanie „zombie” (zob. UWAGI poniżej).
Jeśli stan potomka już uległ zmianie, to te wywołania niezwłocznie powrócą. W przeciwnym przypadku
zablokują, do momentu zmiany stanu potomka lub przerwania wywołania przez procedurę obsługi sygnału
(zakładając, że wywołania systemowe nie są automatycznie uruchamiane ponownie ze względu na znacznik
SA_RESTART sigaction(2)). W pozostałej części niniejszego podręcznika, potomek, którego stan uległ
zmianie, ale na którego jeszcze nie poczekano za pomocą opisywanych wywołań systemowych, będzie określany
terminem oczekiwalnego.
wait() i waitpid()
Wywołanie systemowe wait() wstrzymuje wykonanie wątku wywołującego, dopóki nie zakończy się jeden z jego
potomków. Wywołanie wait(&wstatus) jest równoważne:
waitpid(-1, &wstatus, 0);
Wywołanie systemowe waitpid() wstrzymuje wykonanie wątku wywołującego, dopóki potomek określony
argumentem pid nie zmieni stanu. Domyślnie, waitpid() czeka jedynie na zatrzymanie potomka, lecz to
zachowanie można zmienić argumentem options, jak opisano niżej.
Wartość pid może wynosić:
< -1 oznacza oczekiwanie na dowolnego potomka, którego identyfikator grupy procesów jest równy modułowi
wartości (wartości bezwzględnej) pid.
-1 oznacza oczekiwanie na dowolnego potomka.
0 oznacza oczekiwanie na dowolnego potomka, którego identyfikator grupy procesów jest równy
identyfikatorowi procesu wołającego, w momencie wywołania waitpid().
> 0 oznacza oczekiwanie na potomka, którego PID jest równy wartości pid.
Wartość options jest sumą (OR) zera lub więcej spośród następujących stałych:
WNOHANG
oznacza natychmiastowy powrót z funkcji, jeśli potomek nie zakończył pracy.
WUNTRACED
powraca również, jeśli potomek został zatrzymany (lecz nie śledzony za pomocą ptrace(2)). Status
potomków śledzonych, które są zatrzymane jest zapewniany nawet gdy nie podano tej opcji.
WCONTINUED (od Linuksa 2.6.10)
powraca również, jeśli zatrzymany potomek został wznowiony sygnałem SIGCONT.
(Poniższe opcje dotyczą wyłącznie Linuksa.)
Jeśli wstatus nie wynosi NULL, to wait() i waitpid() przechowują informacje o statusie w int, na którą on
wskazuje. Liczbę tę można sprawdzić następującymi makrami (które jako argument przyjmują nie wskaźnik do
niej, jak czynią to wait() i waitpid(), lecz samą liczbę!):
WIFEXITED(wstatus)
zwraca prawdę, jeśli potomek zakończył się w sposób normalny tj. wywołując exit(3) lub _exit(2)
albo powracając z main().
WEXITSTATUS(wstatus)
zwraca status zakończenia potomka. Składa się on z ośmiu najmniej znaczących bitów argumentu
status, które potomek podał w wywołaniu do exit(3) lub _exit(2) albo argumentu powrotnego z
main(). Makro to może być przetwarzane tylko jeśli WIFEXITED zwróciło prawdę.
WIFSIGNALED(wstatus)
zwraca prawdę, jeśli potomek został zakończony sygnałem.
WTERMSIG(wstatus)
zwraca numer sygnału, który spowodował zakończenie procesu potomnego. Makro to powinno być używane
tylko po zwróceniu prawdy przez WIFSIGNALED.
WIFSTOPPED(wstatus)
zwraca prawdę, jeśli potomek dokonał zrzutu pamięci (zob. core(5)). Makra tego należy używać tylko
wówczas, gdy WIFSIGNALED zwróciło prawdę.
Makro nie jest określone w POSIX.1-2001 i nie jest dostępne w niektórych implementacjach Uniksa
(np. AIX, SunOS). Należy go zatem używać wewnątrz #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(wstatus)
zwraca prawdę, jeśli proces potomny został zatrzymany po dostarczeniu sygnału; jest to możliwe
tylko jeśli wywołanie wykonano z użyciem WUNTRACED lub gdy potomek jest śledzony (zob. ptrace(2)).
WSTOPSIG(wstatus)
zwraca numer sygnału, który spowodował zatrzymanie potomka. Makro to może być użyte tylko, gdy
WIFSTOPPED zwróciło prawdę.
WIFCONTINUED(wstatus)
(od Linuksa 2.6.10) zwraca prawdę, jeśli proces potomny został wznowiony, ze względu na otrzymanie
SIGCONT.
waitid()
Wywołanie systemowe waitid() (dostępne od Linuksa 2.6.9) udostępnia precyzyjniejszą kontrolę nad stanem
potomka, na którego się czeka.
Argumenty idtype i id wybierają potomka (potomków), na którego się oczekuje, jak poniżej:
idtype == P_PID
Oczekuje na potomka, którego PID jest równy id.
idtype == P_PIDFD (od Linuksa 5.4)
Oczekuje na potomka, do którego odnosi się deskryptor pliku PID podany w id (więcej informacji o
deskryptorach pliku PID w podręczniku pidfd_open(2)).
idtype == P_PGID
Oczekuje na dowolnego potomka, którego identyfikator grupy jest równy id. Od Linuksa 5.4, jeśli id
wynosi zero, to oczekuje na dowolnego potomka z tej samej grupy procesów, co grupa procesu
wywołującego w momencie wywołania.
idtype == P_ALL
Oczekuje na dowolnego potomka; id jest ignorowane.
Zmianę statusu potomka, na którego się oczekuje, podaje się za pomocą sumy (OR) jednego lub kilku
poniższych znaczników w options:
WEXITED
Oczekuje na potomka, który został zakończony.
WSTOPPED
Oczekuje na potomka, który został zakończony za pomocą dostarczenia sygnału.
WCONTINUED
Oczekuje na (poprzednio zatrzymanego) potomka, który został wznowiony sygnałem SIGCONT.
Ponadto, w options można zsumować poniższe znaczniki:
WNOHANG
Tak jak w waitpid().
WNOWAIT
Pozostawia potomka w stanie oczekiwalnym; późniejszym wywołaniem oczekiwania można następnie
pobrać informacje o stanie potomka.
Po pomyślnym powrocie, waitid() uzupełnia następujące pola struktury siginfo_t, na którą wskazuje infop:
si_pid Identyfikator procesu potomnego.
si_uid Rzeczywisty identyfikator użytkownika potomka (pole to nie jest ustawione w większości innych
implementacji).
si_signo
Zawsze ustawione na SIGCHLD.
si_status
Status zakończenia potomka, taki jak podany do _exit(2) (lub exit(3)) lub sygnał powodujący
zakończenie, zatrzymanie lub kontynuowanie potomka. Pole si_code może posłużyć do określenia
sposobu interpretacji tego pola.
si_code
Ustawione na jeden z: CLD_EXITED (potomek wywołał _exit(2)); CLD_KILLED (potomek zabity sygnałem);
CLD_DUMPED (potomek zabity sygnałem, zrzucił pamięć); CLD_STOPPED (potomek zatrzymany sygnałem);
CLD_TRAPPED (śledzony potomek wyzwolił pułapkę) lub CLD_CONTINUED (potomek kontynuował po
otrzymaniu SIGCONT).
Jeśli w options podano WNOHANG i nie było potomków w stanie oczekiwalnym, to waitid() zwróci bezzwłocznie
0, natomiast stan struktury siginfo_t, na którą wskazuje infop zależy od implementacji. Aby (w sposób
przenośny) rozróżnić ten przypadek od sytuacji, gdy potomek był w stanie oczekiwalnym, należy wyzerować
pole si_pid przed wywołaniem i sprawdzić, czy wartość pola jest niezerowa, po powrocie wywołania.
POSIX.1-2008 Technical Corrigendum 1 (2013) dodaje wymaganie, że gdy w options podano WNOHANG i nie było
potomków w stanie oczekiwalnym, to waitid() powinno wyzerować pola si_pid i si_signo struktury. W
Linuksie i innych implementacjach, które przestrzegają tego wymagania, nie ma potrzeby zerowania pola
si_pid, przed wywołaniem waitid(). Obecnie, nie wszystkie implementacje przestrzegają jednak tego
wymagania POSIX.1.
WARTOŚĆ ZWRACANA
wait(): po pomyślnym zakończeniu zwraca identyfikator procesu zakończonego potomka, w razie błędu zwraca
-1.
waitpid(): po pomyślnym zakończeniu, zwraca identyfikator procesu, którego stan uległ zmianie; jeśli
podano WNOHANG i jeden lub więcej z potomków podanych w pid istnieje, lecz nie zmienił jeszcze stanu,
zwracane jest 0. W przypadku niepowodzenia, zwracane jest -1.
waitid(): zwraca 0 po pomyślnym zakończeniu lub gdy podano WNOHANG i żaden z potomków podanych w id nie
zmienił jeszcze stanu; w przypadku błędu zwracane jest -1.
W przypadku niepowodzenia, wszystkie wywołania ustawiają errno, wskazując błąd.
BŁĘDY
EAGAIN Deskryptor pliku PID podany w id jest nieblokujący, a proces do którego się odnosi nie zakończył
się.
ECHILD (dla wait()) Proces wywołujący nie ma żadnych potomków, na których jeszcze się nie czeka.
ECHILD (dla waitpid() lub waitid()) Proces o zadanym pid (waitpid()) lub idtype i id (waitid()) nie
istnieje lub nie jest potomkiem procesu wywołującego (może się to zdarzyć również w przypadku
potomka, który ustawił akcję obsługi sygnału SIGCHLD na SIG_IGN; zob. także: wątki w rozdziale
Uwagi linuksowe).
EINTR Nie ustawiono WNOHANG, a został przechwycony niezablokowany sygnał lub SIGCHLD; zob. signal(7).
EINVAL Argument options był niepoprawny.
ESRCH (dla wait() lub waitpid()) pid jest równe INT_MIN.
WERSJE
Różnice biblioteki C/jądra
wait() jest w rzeczywistością funkcją biblioteczną, która (w glibc) jest zaimplementowana jako wywołanie
do wait4(2).
Na niektórych architekturach, nie ma wywołania systemowego waitpid(); zamiast tego interfejs ten jest
zaimplementowany jako opakowująca funkcja biblioteki C, która wywołuje wait4(2).
Surowe wywołanie systemowe waitid() przyjmuje piąty argument, typu struct rusage *. Jeśli argument ten
nie wynosi NULL, to jest używany do zwrócenia informacji o użyciu zasobów potomka, w ten sam sposób jak
wait4(2). Więcej szczegółów w podręczniku getrusage(2).
STANDARDY
POSIX.1-2008.
HISTORIA
SVr4, 4.3BSD, POSIX.1-2001.
UWAGI
Potomek który się zakończy, ale na którego nie oczekiwano staje się „zombie”. Jądro przechowuje minimalny
zbiór informacji o procesach zombie (PID, status zakończenia, informacje o użyciu zasobów), aby pozwolić
później procesowi macierzystemu na wykonanie oczekiwania, aby pozyskać informacje o potomku. Dopóki
zombie nie zostanie usunięty z systemu poprzez oczekiwanie, będzie zajmował miejsce w tablicy procesów
jądra, a jeśli ta tablica się wypełni, nie będzie można tworzyć nowych procesów. Jeśli proces macierzysty
zakończy się, to ewentualni potomkowie „zombie”, zostaną zaadoptowani przez init(1), (lub przez
najbliższy proces dorzynający (ang. subreaper), według definicji użycia operacji PR_SET_CHILD_SUBREAPER
prctl(2)); init(1) automatycznie wykona odczekanie, w celu usunięcia zombie.
POSIX.1-2001 określa, że jeśli jako dyspozycję sygnału SIGCHLD ustawiono na SIG_IGN lub dla SIGCHLD
ustawiono znacznik SA_NOCLDWAIT (zob. sigaction(2)), to kończony potomek nie staje się zombie, a
wywołanie wait() lub waitpid() zablokuje, dopóki wszyscy potomkowie nie zakończą się, a następnie
zawiedzie z errno ustawionym na ECHILD. (Pierwotny standard POSIX pozostawiał zachowanie ustawienia
SIGCHLD na SIG_IGN nieokreślonym. Proszę zauważyć, że choć domyślną dyspozycją SIGCHLD jest
„ignorowanie”, to wyraźne ustawienie dyspozycji na SIG_IGN daje inne zachowanie w stosunku do potomków
procesu zombie).
Linux 2.6 jest zgodny z wymaganiami POSIX. Jednak Linux 2.4 (i wcześniejsze) nie są: jeśli wywołanie
wait() lub waitpid() jest wykonywane z ignorowaniem SIGCHLD, zachowuje się ono tak, jakby SIGCHLD nie
były ignorowane, to znaczy, wywołanie zostaje zablokowane do chwili zakończenia następnego potomka, a
następnie zwraca identyfikator procesu i status tego potomka.
Uwagi linuksowe
Pod Linuksem, wątek zarządzany przez jądro nie jest uruchamiany inaczej niż zwykły proces. Zamiast tego
wątek jest po prostu procesem stworzonym przez wywołanie dostępnej tylko pod Linuksem funkcji systemowej
clone(2). Inne funkcje, jak na przykład przenośne pthread_create(3) są zaimplementowane przez wywołania
funkcji clone(2). W wersjach Linuksa poprzedzających 2.4, wątek był po prostu specyficznym przypadkiem
procesu. W związku z tym nie mógł on czekać na potomków innego wątku nawet w przypadku, gdy ten drugi
wątek należał do tej samej grupy wątków. Jednakże, POSIX zaleca taką funkcjonalność, więc począwszy od
Linuksa 2.4 wątek może (i domyślnie będzie) czekać na potomków innych wątków należących do tej samej
grupy wątków.
Następujące, specyficzne dla Linuksa opcje w options są przeznaczone dla potomków utworzonych za pomocą
clone(2); mogą być one również, od Linuksa 4.7, używane z waitid():
__WCLONE
Oczekuje tylko na potomków typu „clone”. Jeśli opcja ta zostanie pominięta oczekiwanie będzie
występować tylko na potomków typu „nie-clone”. (Potomek typu „clone” to taki, który po zakończeniu
nie dostarcza swojemu procesowi macierzystemu sygnału lub dostarcza sygnał inny niż SIGCHLD.)
Opcja ta jest ignorowana, jeśli ustawiona jest również opcja __WALL.
__WALL (od Linuksa 2.4)
Oczekuje na procesy potomne niezależnie od ich typu („clone” lub „non-clone”).
__WNOTHREAD (od Linuksa 2.4)
Nie oczekuje na procesy potomne innych wątków w obrębie tej samej grupy wątków. Było to w Linuksie
domyślne przed wersją 2.4.
Od Linuksa 4.7, znacznik __WALL jest automatycznie dorozumiany, gdy potomek jest śledzony (ptraced).
USTERKI
Zgodnie z POSIX.1-2008, aplikacje wywołujące waitid() muszą upewnić się, że infop wskazuje na strukturę
siginfo_t (tj. jest nie to pusty wskaźnik). W Linuksie, jeśli infop wynosi NULL, to waitid() kończy się
powodzeniem, zwracając identyfikator procesu oczekiwanego potomka. Aplikacje powinny unikać polegania na
tym niespójnym, niestandardowym i niepotrzebnym zachowaniu.
PRZYKŁADY
Poniższy program demonstruje użycie fork(2) i waitpid(). Program tworzy proces potomny. Jeśli nie poda
się argumentów wiersza poleceń, potomek zawiesza swoje wykonanie za pomocą pause(2), aby pozwolić
użytkownikowi wysyłać sygnały do potomka. W przeciwnym przypadku, gdy poda się argumenty wiersza poleceń,
potomek bezzwłocznie wychodzi, używając liczby podanej w wierszu polecenia jako statusu zakończenia.
Proces macierzysty wykonuje pętlę monitorującą potomka za pomocą waitpid() i używa makr W*() opisanych
powyżej, do analizy wartości statusu oczekiwania.
Poniższa sesja powłoki demonstruje użycie programu:
$ ./a.out &
PID potomka to 32360
[1] 32359
$ kill -STOP 32360
zatrzymany sygnałem 19
$ kill -CONT 32360
wznowiony
$ kill -TERM 32360
zabity sygnałem 15
[1]+ Zakończony ./a.out
$
Kod źródłowy programu
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.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) { /* Kod wykonywany przez potomka */
printf("PID potomka to %jd\n", (intmax_t) getpid());
if (argc == 1)
pause(); /* Oczekiwanie na sygnały */
_exit(atoi(argv[1]));
} else { /* Kod wykonywany przez rodzica */
do {
w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(wstatus)) {
printf("wyszedł, status=%d\n", WEXITSTATUS(wstatus));
} else if (WIFSIGNALED(wstatus)) {
printf("zabity sygnałem %d\n", WTERMSIG(wstatus));
} else if (WIFSTOPPED(wstatus)) {
printf("zatrzymany sygnałem %d\n", WSTOPSIG(wstatus));
} else if (WIFCONTINUED(wstatus)) {
printf("wznowiony\n");
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
exit(EXIT_SUCCESS);
}
}
ZOBACZ TAKŻE
_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)
TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>,
Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać
zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ
ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-
list@lists.sourceforge.net.
Linux man-pages 6.9.1 15 czerwca 2024 r. wait(2)