• WNOWAIT — в обычной ситуации waitid() возвращает статус потомка лишь однократно. Но если указать флаг WNOWAIT, возвращается статус потомка, а сам потомок остается доступным для ожидания, и позже мы можем опять воспользоваться вызовом waitid(), чтобы получить ту же самую информацию.

В случае успеха waitid() возвращает 0, а структуре siginfo_t (см. раздел 21.4), на которую ссылается параметр infop, присваивается информация о потомке. В структуре siginfo_t заполняются следующие поля.

• si_code — содержит одно или несколько значений такого вида: CLD_EXITED (говорит о том, что потомок был завершен путем вызова _exit()), CLD_KILLED (сигнализирует об остановке потомка с помощью сигнала), CLD_STOPPED (указывает на остановку потомка посредством сигнала) или CLD_CONTINUED (говорит о том, что ранее остановленный потомок продолжил выполнение в результате получения сигнала SIGCONT).

• si_pid — содержит идентификатор дочернего процесса, у которого изменилось состояние.

• si_signo — всегда равно SIGCHLD.

• si_status — содержит либо код завершения потомка, переданный в _exit(), либо сигнал, который заставил потомка остановиться, продолжить работу или завершиться. Чтобы определить, с каким именно видом информации мы имеем дело, можно проанализировать значение поля si_code.

• si_uid — содержит реальный пользовательский идентификатор потомка. В большинстве реализаций UNIX оно остается пустым.

В операционной системе Solaris заполняются два дополнительных поля: si_stime и si_utime. Они содержат, соответственно, системное и пользовательское время ЦП, затраченное потомком. Стандарт SUSv3 не требует от вызова waitid() заполнения данных полей.

На одном из аспектов работы вызова waitid() следует остановиться отдельно. Если в аргументе options указан флаг WNOHANG, тогда возвращаемое значение 0 может означать одно из двух: либо потомок уже успел поменять состояние на момент вызова (а информация о нем передается через аргумент infop, указывающий на структуру siginfo_t), либо потомка, чье состояние изменилось, просто не было. Во втором варианте некоторые реализации Unix (включая Linux) обнуляют структуру siginfo_t. Так, сравнивая si_pid с нулем, мы можем различить эти два случая. К сожалению, такой подход не является обязательным с точки зрения стандарта SUSv3 и в некоторых системах UNIX структура siginfo_t остается неизменной (в 2013 году в стандарт SUSv4 было внесено требование, согласно которому в этом случае si_pid и si_signo должны обнуляться). Единственным переносимым способом отличать эти два случая является обнуление структуры siginfo_t перед вызовом waitid(), как показано в следующем коде:

siginfo_t info;

memset(&info, 0, sizeof(siginfo_t));

if (waitid(idtype, id, &info, options | WNOHANG) == –1)

errExit("waitid");

if (info.si_pid == 0) { /* Ни один из потомков не изменил состояние */

} else {

/* Потомок изменил состояние: подробности доступны в 'info' */

}

26.1.6. Системные вызовы wait3() и wait4()

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

#define _BSD_SOURCE /* Или #define _XOPEN_SOURCE 500 для wait3() */

#include

#include

pid_t wait3(int *status, int options, struct rusage *rusage);

pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);

Оба вызова возвращают идентификатор потомка или –1 при ошибке

Если не считать наличия аргумента rusage, вызов wait3() эквивалентен следующему вызову waitpid():

waitpid(–1, &status, options);

Аналогично ниже представлен эквивалент вызова wait4():

waitpid(pid, &status, options);

Иными словами, wait3() ожидает любого потомка, а с помощью wait4() можно ждать определенных дочерних процессов.

В некоторых реализациях UNIX вызовы wait3() и wait4() возвращают сведения о потреблении ресурсов только для завершенных потомков. В Linux также может быть доступна информация об остановленных дочерних процессах, если в аргументе options указан флаг WUNTRACED.

Имена этих двух системных вызовов связаны с количеством принимаемых ими аргументов. Оба они берут свое начало в системе BSD, но в наши дни доступны в большинстве реализаций UNIX. Ни один из них не входит в стандарт SUSv3 (wait3() был описан в стандарте SUSv2, с пометкой LEGACY).

В этой книге мы, как правило, избегаем использования данных вызовов. В большинстве случаев нам не нужна дополнительная информация, которую они возвращают. К тому же нехватка стандартизации ограничивает их переносимость.

26.2. Процессы-«сироты» и процессы-«зомби»
Перейти на страницу:

Похожие книги