Provided by: manpages-ru-dev_4.21.0-2_all bug

ИМЯ

       wait, waitpid, waitid - ожидает смену состояния процесса

LIBRARY

       Standard C library (libc, -lc)

СИНТАКСИС

       #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);
                       /* Это интерфейс glibc и POSIX; информацию по
                          системному вызову ядра смотрите в ЗАМЕЧАНИЯ. */

   Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

       waitid():
           Since glibc 2.26:
               _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L
           glibc 2.25 and earlier:
               _XOPEN_SOURCE
                   || /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
                   || /* glibc <= 2.19: */ _BSD_SOURCE

ОПИСАНИЕ

       Данные  системные  вызовы  используются  для ожидания изменения состояния процесса-потомка
       вызвавшего процесса и получения информации о потомке,  чьё  состояние  изменилось.  Сменой
       состояния  считается:  прекращение работы потомка, останов потомка по сигналу, продолжение
       работы  потомка  по  сигналу.  Ожидание  прекращения  работы  потомка  позволяет   системе
       освободить   ресурсы,   использовавшиеся   потомком;  если  ожидание  не  выполняется,  то
       прекративший работу потомок остаётся в системе в состоянии "зомби (zombie)" (см. ЗАМЕЧАНИЯ
       далее).

       Если  состояние  потомка  уже изменилось, то вызов сразу возвращает результат. В противном
       случае, работа приостанавливается до тех  пор,  пока  не  произойдёт  изменение  состояния
       потомка  или обработчик сигналов не прервёт вызов (предполагается, что системные вызовы не
       перезапускаются  автоматически  из-за  указания  флага  SA_RESTART  в   sigaction(2)).   В
       оставшейся  части  страницы  потомок,  чьё  состояние  ещё  не было получено одним из этих
       системных вызовов, называется ожидаемым (waitable).

   wait() и waitpid()
       Системный вызов wait() приостанавливает выполнение вызвавшей нити  до  тех  пор,  пока  не
       прекратит выполнение один из её потомков. Вызов wait(&wstatus) эквивалентен:

           waitpid(-1, &wstatus, 0);

       Системный  вызов  waitpid() приостанавливает выполнение вызвавшей нити до тех пор, пока не
       изменится состояние потомка, заданного аргументом  pid.  По  умолчанию  waitpid()  ожидает
       только  прекращения  работы  потомка,  но  это  можно  изменить через аргумент options как
       описано далее.

       Значением pid может быть:

       < -1   означает, что нужно ждать любого потомка, чей идентификатор группы процессов  равен
              абсолютному значению pid.

       -1     означает, что нужно ждать любого потомка.

       0      meaning  wait  for any child process whose process group ID is equal to that of the
              calling process at the time of the call to waitpid().

       > 0    означает, что нужно ждать любого потомка, чей идентификатор процесса равен pid.

       Значение options создаётся путем битовой операции ИЛИ над следующими константами:

       WNOHANG
              означает немедленный возврат, если ни один потомок не завершил выполнение.

       WUNTRACED
              также возвращаться, если есть  остановленный  потомок  (но  не  трассируемый  через
              ptrace(2)).  Состояние  трассируемого  остановленного  потомка предоставляется даже
              если этот аргумент не указан.

       WCONTINUED (начиная с Linux 2.6.10)
              также  возвращаться,  если  работа  остановленного  потомка   возобновилась   из-за
              получения сигнала SIGCONT.

       (Аргументы, имеющиеся только в Linux, см. далее.)

       Если  wstatus  не  равен  NULL,  то  wait() и waitpid() сохраняют информацию о состоянии в
       переменной типа int, на которую указывает wstatus. Это целое  число  можно  исследовать  с
       помощью  следующих макросов (они принимают в качестве аргумента само целое, а не указатель
       на него как wait() и waitpid()!):

       WIFEXITED(wstatus)
              возвращает истинное значение, если потомок нормально  завершился,  то  есть  вызвал
              exit(3) или _exit(2), или вернулся из функции main().

       WEXITSTATUS(wstatus)
              возвращает  код  завершения  потомка.  Он  состоит  из восьми младших бит аргумента
              status, который потомок указал при вызове exit(3)  или  _exit(2)  или  в  аргументе
              оператора  return  в  функции  main().  Этот макрос можно использовать, только если
              WIFEXITED вернул истинное значение.

       WIFSIGNALED(wstatus)
              возвращает истинное значение, если потомок завершился из-за сигнала.

       WTERMSIG(wstatus)
              возвращает номер сигнала, который привел к завершению потомка.  Этот  макрос  можно
              использовать, только если WIFSIGNALED вернул истинное значение.

       WCOREDUMP(wstatus)
              возвращает  истину, если потомок создал дамп памяти (смотрите core(5)). Этот макрос
              можно использовать только, если при WIFSIGNALED возвращается истинное значение.

              Данный макрос не описан в POSIX.1-2001 и недоступен в  некоторых  реализациях  UNIX
              (например, AIX, SunOS). Поэтому указывайте его внутри #ifdef WCOREDUMP ... #endif.

       WIFSTOPPED(wstatus)
              возвращает  истинное  значение,  если  потомок  остановлен по сигналу; это возможно
              только, если при вызове был указан флаг WUNTRACED или если над потомком выполняется
              трассировка (см. ptrace(2)).

       WSTOPSIG(wstatus)
              возвращает  номер сигнала, из-за которого потомок был остановлен. Этот макрос можно
              использовать только, если при WIFSTOPPED возвращается истинное значение.

       WIFCONTINUED(wstatus)
              (начиная с Linux 2.6.10)  возвращает  истинное  значение,  если  потомок  продолжил
              работу, получив сигнал SIGCONT.

   waitid()
       Системный  вызов  waitid()  (доступен,  начиная  с Linux 2.6.9) предоставляет более полный
       контроль над тем, какого изменения состояния нужно ждать у потомка.

       Аргументы idtype и id определяют какого(их) потомков ждать:

       idtype == P_PID
              Ждать потомка, чей ID процесса совпадает с id.

       idtype == P_PIDFD (начиная с Linux 5.4)
              Wait for the child referred to by the PID file descriptor specified  in  id.   (See
              pidfd_open(2)  for further information on PID file descriptors.)

       idtype == P_PGID
              Wait  for  any  child whose process group ID matches id.  Since Linux 5.4, if id is
              zero, then wait for any child that is in the same process  group  as  the  caller's
              process group at the time of the call.

       idtype == P_ALL
              Ждать любого потомка; значение id игнорируется.

       Ожидаемые изменения состояния потомков задаются следующими флагами в options (объединяются
       через OR):

       WEXITED
              Ждать завершения потомков.

       WSTOPPED
              Ждать потомков, которые завершатся по получению сигнала.

       WCONTINUED
              Ждать возобновления работы потомков (ранее  остановленных)  при  получении  сигнала
              SIGCONT.

       Дополнительно с помощью OR в options могут задаваться следующие флаги:

       WNOHANG
              Как в waitpid().

       WNOWAIT
              Оставить потомка в состоянии ожидания; последующий вызов wait сможет снова получить
              информацию о состоянии потомка.

       При  успешном  возврате,  waitid()  заполняет  следующие  поля  в   структуре   siginfo_t,
       указываемой из infop:

       si_pid ID процесса потомка.

       si_uid Реальный пользовательский ID потомка. (Это поле не заполняется в большинстве других
              реализаций.)

       si_signo
              Всегда устанавливается в SIGCHLD.

       si_status
              Заполняется кодом завершения потомка, заданном в  _exit(2)  (или  в  exit(3)),  или
              номером  сигнала,  который  прервал,  остановил  или  продолжил работу потомка. Что
              записано в данном поле можно определить по значению поля si_code.

       si_code
              Устанавливается  в  одно  из:  CLD_EXITED  (потомок  вызвал  _exit(2));  CLD_KILLED
              (потомок  завершил  работу  по  сигналу);  CLD_DUMPED  (потомок  завершил работу по
              сигналу и был создан дамп памяти); CLD_STOPPED (потомок приостановлен по  сигналу);
              CLD_TRAPPED   (трассируемый  потомок  был  захвачен);  или  CLD_CONTINUED  (потомок
              продолжил работу по сигналу SIGCONT).

       Если в options указан флаг WNOHANG и нет потомков в состоянии ожидания, то waitid()  сразу
       возвращает  0,  а  состояние  структуры  siginfo_t, на которую указывает infop, зависит от
       реализации. Чтобы (точно) отличать этот случай  от  того,  что  потомок  был  в  ожидаемом
       состоянии,  обнулите  поле si_pid перед вызовом и проверьте ненулевое значение в этом поле
       после отработки вызова.

       В POSIX.1-2008 Technical Corrigendum 1  (2013)  добавлено  требование,  что  при  указании
       WNOHANG в options и нет потомков в состоянии ожидания, то вызов waitid() должен возвращать
       в структуре обнулённые поля si_pid и si_signo. В Linux и других реализациях придерживаются
       этого  требования,  поэтому не нужно обнулять поле si_pid перед вызовом waitid(). Однако в
       этом не все реализации следуют POSIX.1.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

       wait(): on success, returns the process ID of the terminated  child;  on  failure,  -1  is
       returned.

       waitpid():  on  success,  returns  the process ID of the child whose state has changed; if
       WNOHANG was specified and one or more child(ren) specified by pid exist, but have not  yet
       changed state, then 0 is returned.  On failure, -1 is returned.

       waitid():  returns 0 on success or if WNOHANG was specified and no child(ren) specified by
       id has yet changed state; on failure, -1 is returned.

       On failure, each of these calls sets errno to indicate the error.

ОШИБКИ

       EAGAIN The PID file descriptor specified in id is nonblocking  and  the  process  that  it
              refers to has not terminated.

       ECHILD (для wait()) У вызвавшего процесса нет ожидающих потомков.

       ECHILD (для  waitpid()  или  waitid())  Процесс,  заданный pid (waitpid()) или idtype и id
              (waitid()), не существует или не является потомком вызвавшего процесса. (Это  может
              случиться  для своего потомка, если действие для SIGCHLD установлено в SIG_IGN. См.
              также раздел Linux Notes о нитях.)

       EINTR  Флаг WNOHANG не задан и был пойман неблокируемый сигнал или SIGCHLD; см. signal(7).

       EINVAL Недопустимое значение options.

       ESRCH  (for wait()  or waitpid())  pid is equal to INT_MIN.

СТАНДАРТЫ

       SVr4, 4.3BSD, POSIX.1-2001.

ЗАМЕЧАНИЯ

       Потомок, который завершился, но которого  не  ждали,  становится  «зомби»  (zombie).  Ядро
       поддерживает  минимальный  набор  информации о процессах зомби (PID, состояние завершения,
       использованные ресурсы), чтобы позже позволить родителю  выполнить  процесс  ожидания  для
       получения  информации  о  потомке. До тех пор, пока зомби не будет удалён из системы через
       процесс ожидания (wait), он занимает пространство (slot) в таблице процессов ядра, и  если
       таблица  заполнится, станет невозможно создавать новые процессы. Если родительский процесс
       завершает работу, то его потомки «зомби» (если есть) усыновляются процессом  init(1)  (или
       ближайшим    «сборщиком»,    определённым    посредством    вызова   prctl(2)с   операцией
       PR_SET_CHILD_SUBREAPER); init(1) автоматически выполняет процедуру ожидания  для  удаления
       зомби.

       В  POSIX.1-2001  указано,  что  если  для  SIGCHLD  указан  флаг  SIG_IGN или SA_NOCLDWAIT
       (смотрите sigaction(2)), то завершающиеся потомки не становятся зомби, а вызов wait()  или
       waitpid()  заблокирует выполнение до тех пор, пока все потомки не завершат работу, и затем
       завершится с ошибкой errno, равной ECHILD (в оригинальном стандарте POSIX  такое  значение
       настройки  SIGCHLD  в  SIG_IGN  не  определено.  Заметим,  что  хотя  поведение SIGCHLD по
       умолчанию является «игнорирование», явная установка в SIG_IGN приводит другому обращению с
       потомками зомби).

       Linux 2.6 соответствует данной спецификации. Однако, Linux 2.4 (и ранее) не соответствует:
       если вызов wait() или waitpid() сделан при игнорировании SIGCHLD, вызов работает как  если
       бы  SIGCHLD  не  игнорировался, то есть, вызов блокирует работу до тех пор, пока следующий
       потомок не завершит работу и затем возвращает ID процесса и состояние этого потомка.

   Замечания, касающиеся Linux
       В ядре Linux нити, управляемые ядром, устройством не отличаются от процесса.  Нить  —  это
       просто  процесс, который создан уникальным (существующим только в Linux) системным вызовом
       clone(2);  другие  процедуры,  такие  как  переносимая  версия  pthread_create(3),   также
       реализованы  с  помощью clone(2). До Linux 2.4, нить представляла собой специализированный
       вариант процесса, и, как следствие, нить не могла ждать потомков другой нити,  даже  когда
       последняя   принадлежала   той   же   группе   нитей.   Однако,   в  POSIX  вписали  такую
       функциональность, и, начиная с Linux 2.4, нить может, и по умолчанию будет ждать  потомков
       других нитей в той же группе нитей.

       Следующие  значения options, присущие только Linux, используются для потомков, созданных с
       помощью clone(2); начиная с Linux 4.7, они также могут использоваться с waitid():

       __WCLONE
              Ждать только «клонированных (clone)» потомков. Если не указано, то ожидаются только
              «не   клонированные»   потомки   («клонированным»  считается  потомок,  который  не
              доставляет  сигнал,  или  сигнал,  отличный  от  SIGCHLD,   своему   родителю   при
              завершении). Этот аргумент игнорируется, если также указано __WALL.

       __WALL (начиная с Linux 2.4)
              Ждать всех потомков независимо от типа ("клонированный" или "неклонированный").

       __WNOTHREAD (начиная с Linux 2.4)
              Не ждать потомков других нитей в той же группе нитей. Это поведение по умолчанию до
              Linux 2.4.

       Начиная с Linux 4.7, в случае, когда потомок был вызван  с  помощью  ptrace,  флаг  __WALL
       назначается автоматически.

   Отличия между библиотекой C и ядром
       В  действительности,  wait()  —  библиотечная функция, которая (в glibc) реализована через
       вызов wait4(2).

       Для  некоторых  архитектур  нет  системного  вызова  waitpid();  его  заменяет  интерфейс,
       реализованный через обёрточную функцию библиотеки C, которая вызывает wait4(2).

       Системный  вызов  ядра  waitid()  имеет  пятый  аргумент с типом struct rusage *. Если его
       значение не равно NULL,  то  он  используется  для  возврата  информации  по  используемым
       ресурсам в потомке, в том же виде что и wait4(2). Подробности смотрите в getrusage(2).

ДЕФЕКТЫ

       Согласно  POSIX.1-2008,  приложение,  вызывающее  waitid(),  должно  убедиться,  что infop
       указывает на структуру siginfo_t (т. е., что это указатель не равен null). В  Linux,  если
       infop  равно  NULL,  то waitid() выполняется успешно и возвращает ID процесса ожидавшегося
       потомка. Приложения не должны полагаться на это несогласованное, нестандартное и  ненужное
       свойство.

ПРИМЕРЫ

       В  следующей  программе  показано  использование  fork(2)  и  waitpid(). Программа создаёт
       процесс потомок. Если программа  запущена  без  параметров,  то  потомок  приостанавливает
       выполнение с помощью pause(2), чтобы позволить пользователю послать сигнал потомку. Иначе,
       если в командной строке задан параметр,  то  потомок  завершает  работу  сразу,  используя
       переданное  в  параметре командной строки целое число как код завершения. Процесс родитель
       работает в цикле, следя за потомком  с  помощью  waitpid(),  и  использует  макросы  W*(),
       описанные ранее, для анализа значения состояния ожидания.

       Следующий сеанс работы в оболочке показывает работу с программой:

           $ ./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 executed by child */
               printf("Child PID is %jd\n", (intmax_t) getpid());
               if (argc == 1)
                   pause();                    /* Wait for signals */
               _exit(atoi(argv[1]));

           } else {                    /* Код, выполняемый родителем */
               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)

ПЕРЕВОД

       Русский   перевод   этой    страницы    руководства    был    сделан    Azamat    Hackimov
       <azamat.hackimov@gmail.com> и Yuri Kozlov <yuray@komyakino.ru>

       Этот  перевод  является  бесплатной  документацией;  прочитайте  Стандартную  общественную
       лицензию GNU версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если  вы  обнаружите  ошибки  в  переводе этой страницы руководства, пожалуйста, отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.