• 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 *
pid_t wait4(pid_t
Оба вызова возвращают идентификатор потомка или –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).
В этой книге мы, как правило, избегаем использования данных вызовов. В большинстве случаев нам не нужна дополнительная информация, которую они возвращают. К тому же нехватка стандартизации ограничивает их переносимость.