Давайте рассмотрим простой обработчик сигнала в действии под Solaris. Следующая программа, ch10-catchint.c
, перехватывает SIGINT
. Обычно вы генерируете этот сигнал, набирая на клавиатуре CTRL-C.
1 /* ch10-catchint.c - перехват SIGINT, по крайней мере, однажды. */
2
3 #include
4 #include
5 #include
6
7 /* handler --- простой обработчик сигнала. */
8
9 void handler(int signum)
10 {
11 char buf[200], *cp;
12 int offset;
13
14 /* Пройти через это испытание , чтобы избежать fprintf(). */
15 strcpy(buf, "handler: caught signal ");
16 cp = buf + strlen(buf); /* cp указывает на завершающий '\0' */
17 if (signum > 100) /* маловероятно */
18 offset = 3;
19 else if (signum > 10)
20 offset = 2;
21 else
22 offset = 1;
23 cp += offset;
24
25 *cp-- = '\0'; /* завершить строку */
26 while (signum >0) { /* work backwards, filling in digits */
27 *cp-- = (signum % 10) + '0';
28 signum /= 10;
29 }
30 strcat(buf, "\n");
31 (void)write(2, buf, strlen(buf));
32 }
33
34 /* main --- установить обработку сигнала и войти в бесконечный цикл */
35
36 int main(void)
37 {
38 (void)signal(SIGINT, handler);
39
40 for(;;)
41 pause(); /* ждать сигнал, см. далее в главе */
42
43 return 0;
44 }
Строки 9–22 определяют функцию обработки сигнала (остроумно названную handler()
[106]). Все, что эта функция делает, — выводит номер перехваченного сигнала и возвращается. Для вывода этого сообщения она выполняет множество ручной работы, поскольку fprintf()
не является «безопасной» для вызова из обработчика сигнала. (Вскоре это будет описано в разделе 10.4.6 «Дополнительные предостережения».)
Функция main()
устанавливает обработчик сигнала (строка 38), а затем входит в бесконечный цикл (строки 40–41). Вот что происходит при запуске:
$ ssh solaris.example.com
/* Зарегистрироваться на доступной системе Solaris */
Last login: Fri Sep 19 04:33:25 2003 from 4.3.2.1.
Sun Microsystems Inc. SunOS 5.9 Generic May 2002
$ gcc ch10-catchint.c /* Откомпилировать программу */
$ a.out /* Запустить ее */
^C handler: caught signal 2 /* Набрать ^C, вызывается обработчик */
^C /* Попробовать снова, но на этот раз... */
$ /* Программа завершается */
Поскольку V7 и другие традиционные системы восстанавливают действие сигнала по умолчанию, поэтому когда вы хотите снова получить сигнал в будущем, функция обработчика должна немедленно переустановить саму себя:
void handler(int signum) {
char buf[200], *cp;
int offset;
(void)signal(signum, handler); /* переустановить обработчик */
/* ...оставшаяся часть функции как прежде... */
}
10.4.2. BSD и GNU/Linux
BSD 4.2 изменила способ работы signal()
.[107] На системах BSD обработчик сигнала после его возвращения остается на месте. Системы GNU/Linux следуют поведению BSD. Вот что происходит под GNU/Linux:
$ ch10-catchint /* Запустить программу */
handler: caught signal 2 /* Набираем ^C, вызывается обработчик */
handler: caught signal 2 /* И снова... */
handler: caught signal 2 /* И снова! */
handler: caught signal 2 /* Помогите! */
handler: caught signal 2 /* Как нам это остановить?! */
Quit (core dumped) /* ^\, генерирует SIGQUIT. Bay */