Роббинс Арнольд
Шрифт:
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 --- разрешение различных событий, которые могут случиться с потомком */
124
125 void manage(siginfo_t *si)
126 {
127 char buf[100];
128
129 switch (si->si_code) {
130 case CLD_STOPPED:
131 write(1, "\tchild stopped, restarting\n", 27);
132 kill(si->si_pid, SIGCONT);
133 break;
134
135 case CLD_CONTINUED: /* not sent on Linux */
136 write(1, "\tchild continued\n", 17);
137 break;
138
139 case CLD_EXITED:
140 strcpy(buf, "\tchild exited with status ");
141 strcat(buf, format_num(si->si_status));
142 strcat(buf, "\n");
143 write(1, buf, strlen(buf));
144 exit(0); /* we're done */
145 break;
146
147 case CLD_DUMPED:
148 write(1, "\tchild dumped\n", 14);
149 break;
150
151 case CLD_KILLED:
152 write(1, " \tchild killed\n", 14);
153 break;
154
155 case CLD_TRAPPED:
156 write(1, "\tchild trapped\n", 15);
157 break;
158 }
159 }
Посредством функции
manage
родитель обрабатывает изменение состояния в порожденном процессе, manage
вызывается, когда изменяется состояние и когда порожденный процесс завершился. Строки 130–133 обрабатывают случай, когда потомок остановился; родитель возобновляет его, посылая
SIGCONT
.