57 if ((ret = waitpid(kids[i], &status, WNOHANG)) == kids[i]) {
58 strcpy(buf, "\treaped process ");
59 strcat(buf, format_num(ret));
60 strcat(buf, "\n");
61 write(1, buf, strlen(buf));
62 kids[i] = NOT_USED;
63 } else if (ret == 0) {
64 strcpy(buf, "\tpid ");
65 strcat(buf, format_num(kids[i]));
66 strcat(buf, " not available yet\n");
67 write(1, buf, strlen(buf));
68 } else if (ret == -1 && errno == EINTR) {
69 write(1, "\tretrying\n", 10);
70 goto retry;
71 } else {
72 strcpy(buf, "\twaitpid failed: ");
73 strcat(buf, strerror(errno));
74 strcat(buf, "\n");
75 write(1, buf, strlen(buf));
76 }
77 }
78 write(1, exited, strlen(exited));
79 }
Строки 51 и 58 выводят «входное» и «завершающее» сообщения, так что мы можем ясно видеть, когда вызывается обработчик сигнала. Другие сообщения начинаются с ведущего символа TAB.
Главной частью обработчика сигнала является большой цикл, строки 52–77. Строки 53–54 проверяют на
NOT_USED
и продолжают цикл, если текущий слот не используется.
Строка 57 вызывает
waitpid
с PID текущего элемента
kids
. Мы предусмотрели опцию
WNOHANG
, которая заставляет
waitpid
возвращаться немедленно, если затребованный потомок недоступен. Этот вызов необходим, так как возможно, что не все потомки завершились.
Основываясь на возвращенном значении, код предпринимает соответствующее действие. Строки 57–62 обрабатывают случай обнаружения потомка, выводя сообщение и помещая в соответствующий слот в
kids
значение
NOT_USED
.
Строки 63–67 обрабатывают случай, когда затребованный потомок недоступен. В этом случае возвращается значение 0, поэтому выводится сообщение, и выполнение продолжается.
Строки 68–70 обрабатывают случай, при котором был прерван системный вызов. В этом случае самым подходящим способом обработки является
goto
обратно на вызов
waitpid
. (Поскольку
main
блокирует все сигналы при вызове обработчика сигнала [строка 96], это прерывание не должно случиться. Но этот пример показывает, как обработать все случаи.)