Provided by: manpages-pl-dev_4.23.1-1_all bug

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
       ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩   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⟩.