Чтение онлайн

ЖАНРЫ

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

Строка 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
.

Строки 135–137 выводят уведомление о возобновлении потомка. Это событие на системах GNU/Linux не происходит, и стандарт POSIX использует в этом случае невыразительный язык, просто говоря, что это событие может появиться, а не появится.

Строки 139–145 обрабатывают случай, когда порожденный процесс завершается, выводя статус завершения. Для этой программы родитель также все сделал, поэтому код завершается, хотя в более крупной программе это не то действие, которое должно быть сделано.

Другие случаи более специализированные. В случае события

CLD_KILLED
для получения дополнительных сведений было бы полезным значение
status
, заполненной функцией
waitpid
.

Вот что происходит при запуске:

$ ch10-status /* Запуск программы */

waiting for signals

Entered childhandler /* Вход в обработчик сигнала */

pid 24279 changed status

child stopped, restarting /* Обработчик действует */

Exited childhandler

waiting for signals

– --> child restarted <--- /*
Из потомка */

Entered childhandler

reaped process 24279 /* Обработчик родителя опрашивает потомка */

child exited with status 42

К сожалению, поскольку нет способа гарантировать доставку по одному

SIGCHLD
на каждый процесс, ваша программа должна быть готова восстановить несколько потомков за один проход.

10.9. Сигналы, передающиеся через

fork
и
exec

Когда программа вызывает

fork
, ситуация с сигналами в порожденном процессе почти идентична ситуации в родительском процессе. Установленные обработчики остаются на месте, заблокированные сигналы остаются заблокированными и т.д. Однако, любые ожидающие в родителе сигналы в потомке сбрасываются, включая установленный с помощью
alarm
временной интервал. Это просто, и это имеет смысл.

Когда процесс вызывает одну из функций

exec
, положение в новой программе следующее:

• Сигналы с установленным действием по умолчанию остаются с этим действием по умолчанию.

• Все перехваченные сигналы сбрасываются в состояние с действием по умолчанию.

• Сигналы, которые игнорируются, продолжают игнорироваться. Особым случаем является

SIGCHLD
. Если
SIGCHLD
до вызова
exec
игнорировался, он может игнорироваться также и после вызова. В качестве альтернативы для него может быть восстановлено действие по умолчанию. То, что происходит на самом деле, стандартом POSIX намеренно не определяется. (Справочные страницы GNU/Linux не определяют, что делает Linux, и поскольку POSIX оставляет это не определенным, любой код, который вы пишете для использования
SIGCHLD
, должен быть подготовлен для обработки любого случая.)

• Сигналы, заблокированные до вызова

exec
, остаются заблокированными и после вызова. Другими словами, новая программа наследует маску сигналов существующего процесса.

• Любые ожидающие сигналы (те, которые появились, но были заблокированы) сбрасываются. Новая программа не может их получить.

• Временной интервал, остающийся для

alarm
, сохраняется на своем месте. (Другими словами, если процесс устанавливает
alarm
, а затем непосредственно вызывает
exec
, новый образ в конечном счете получит
SIGALARM
. Если он сначала вызывает
fork
, родитель сохраняет установки
alarm
, тогда как потомок, вызывающий
exec
, не сохраняет.

ЗАМЕЧАНИЕ. Многие, если не все. программы предполагают, что сигналы инициализированы действиями по умолчанию и что заблокированных сигналов нет. Таким образом, особенно если не вы писали программу, запускаемую с помощью

exec
, можно разблокировать перед вызовам
exec
все сигналы

10.10. Резюме

«Наша история до настоящего времени, эпизод III»

– Арнольд Роббинс (Arnold Robbins) -
Поделиться с друзьями: