Linux программирование в примерах
Шрифт:
10.4.5. Состояния гонок и
Пока обработка одного сигнала за раз выглядит просто: установка обработчика сигнала в
Но что произойдет, если возникнут два идентичных сигнала, один за другим? В частности, что, если ваша система восстановит действие по умолчанию для вашего сигнала, а второй сигнал появится после вызова обработчика, но до того, как он себя восстановит?
Или предположим, что вы используете
Оба случая относятся к состоянию гонки. Одним решением для этих проблем является как можно большее упрощение обработчиков сигналов. Это можно сделать, создав флаговые переменные, указывающие на появление сигнала. Обработчик сигнала устанавливает переменную в true и возвращается. Затем основная логика проверяет флаговую переменную в стратегических местах:
(Обратите внимание, что эта стратегия уменьшает окно уязвимости, но не устраняет его).
Стандарт С вводит специальный тип —
Наличие особого типа является лишь частью истории. Переменные
Ключевое слово
Структурирование приложения исключительно вокруг переменных
10.4.6. Дополнительные предостережения
Стандарт POSIX предусматривает для обработчиков сигналов несколько предостережений:
• Что случается, когда возвращаются обработчики для
• Если обработчик был вызван в результате вызова
• Обработчики сигналов могут вызвать лишь функции из табл. 10.2. В частности, они должны избегать функций
Список в табл. 10.2 происходит из раздела 2.4 тома System Interfaces (Системные интерфейсы) стандарта POSIX 2001. Многие из этих функций относятся к сложному API и больше не рассматриваются в данной книге.
Таблица 10.2. Функции, которые могут быть вызваны из обработчика сигнала
| _Exit | fpathconf | raise | sigqueue |
| _exit | fstat | read | sigset |
| accept | fsync | readlink | sigsuspend |
| access | ftruncate | recv | sleep |
| aio_error | getegid | recvfrom | socket |
| aio_return | geteuid | recvmsg | socketpair |
| aio_suspend | getgid | rename | stat |
| alarm | getgroups | rmdir | sysmlink |
| bind | getpeername | select | sysconf |
| cfgetispeed | getpgrp | sem_post | tcdrain |
| cfgetospeed | getpid | send | tcflow |
| cfsetispeed | getppid | sendmsg | tcflush |
| cfsetospeed | getsockname | sendto | tcgetattr |
| chdir | getsockopt | setgid | tcgetpgrp |
| chmod | getuid | setpgid | tcsendbreak |
| chown | kill | setsid | tcsetattr |
| clock_gettime | link | setsockopt | tcsetpgrp |
| close | listen | setuid | time |
| connect | lseek | shutdown | timer_getoverrun |
| creat | lstat | sigaction | timer_gettime |
| dup | mkdir | sigaddset | timer_settime |
| dup2 | mkfifo | sigdelset | times |
| execle | open | sigemptyset | umask |
| execve | pathconf | sigfillset | uname |
| fchmod | pause | sigismember | unlink |
| fchown | pipe | signal | utime |
| fcntl | poll | sigpause | wait |
| fdatasync | posix_trace_event | sigpending | waitpid |
| fork | pselect | sigprocmask | write |
10.4.7. Наша история до настоящего времени, эпизод 1
Сигналы являются сложной темой, и она становится еще более сбивающей с толку. Поэтому давайте на время сделаем остановку, сделаем шаг назад и подведем итог обсужденному до сих пор:
• Сигналы являются указанием того, что произошло некоторое внешнее событие.
•
•
• Когда сигнал перехватывается, вызывается функция-обработчик. Вот где сложность начинает поднимать свою безобразную голову:
• ISO С не определяет, восстанавливается ли диспозиция сигнала по умолчанию до вызова обработчика или она остается на месте. Первое является поведением V7 и современных систем System V, таких, как Solaris. Последнее является поведением BSD, используемым также в GNU/Linux. (Для форсирования поведения BSD может использоваться функция POSIX