Обработчик сигнала похож на показанные ранее. Обратите внимание на список аргументов (строка 39)
и на то, что нет цикла.
Строки 49–54 обрабатывают завершение процесса, включая вызов
manage
для вывода состояния.
Строки 55–60 обрабатывают случай неожиданного завершения потомка. Этого не должно происходить, поскольку обработчику сигнала передается специфическая для определенного порожденного процесса информация.
Строки 61–66 представляют для нас интерес: возвращаемое значение для изменений состояния равно 0.
manage
имеет дело с деталями (строка 66).
Строки 67–69 обрабатывают прерывания, а строки 70–75 распоряжаются ошибками
80 /* child --- что сделать в порожденном процессе */
81
82 void child(void)
83 {
84 raise(SIGCONT); /* должен быть проигнорирован */
85 raise(SIGSTOP); /* заснуть, родитель снова разбудит */
86 printf("\t---> child restarted <---\n");
87 exit(42); /* нормальное завершение, дать возможность родителю получить значение */
88 }
Функция
child
обрабатывает поведение порожденного процесса, предпринимая действия для уведомления родителя [113] . Строка 84 посылает
SIGCONT
, что может вызвать получение родителем события
CLD_CONTINUED
. Строка 85 посылает
SIGSTOP
, который останавливает процесс (сигнал не может быть перехвачен) и вызывает для родителя событие
CLD_STOPPED
. Когда родитель возобновляет порожденный процесс, последний выводит сообщение, что он снова активен, а затем завершается с известным статусом завершения.
113
Возможно, лучшим именем для функции было бы
child_at_school
[ребенок_в_школе] — Примеч. автора.
90 /* main --- установка относящихся к порожденному процессу сведений
и сигналов, создание порожденного процесса */
91
92 int main(int argc, char **argv)
93 {
94 pid_t kid;
95 struct sigaction sa;
96 sigset_t childset, emptyset;
97
98 sigemptyset(&emptyset);
99
100 sa.sa_flags = SA_SIGINFO;
101 sa.sa_sigaction = childhandler;
102 sigfillset(&sa.sa_mask); /*
при вызове обработчика все заблокировать */
103 sigaction(SIGCHLD, &sa, NULL);
104
105 sigemptyset(&childset);
106 sigaddset(&childset, SIGCHLD);
107
108 sigprocmask(SIG_SETMASK, &childset, NULL); /* блокировать его в коде main */
109
110 if ((kid = fork) == 0)
111 child;
112
113 /* здесь выполняется родитель */
114 for (;;) {
115 printf("waiting for signals\n");
116 sigsuspend(&emptyset);
117 }
118
119 return 0;
120 }
Программа
main
все устанавливает. Строки 100–103 помещают на место обработчик. Строка 100 устанавливает флаг
SA_SIGINFO
таким образом, что используется обработчик с тремя аргументами. Строки 105–108 блокируют
SIGCHLD
.
Строка 110 создает порожденный процесс. Строки 113–117 продолжаются в родителе, используя для ожидания входящих сигналов
sigsuspend
.
123 /* manage --- разрешение различных событий, которые могут случиться с потомком */