plucky (2) waitpid.2.gz

Provided by: manpages-pl-dev_4.25.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⟩.