Разработка приложений в среде Linux. Второе издание
Шрифт:
1. Семантика некоторых сигналов ограничивает, когда они могут быть посланы. Так, например,
2. Если процесс находится в процессе обработки некоторого сигнала, то обработчик сигнала не вызывается повторно для обработки того же сигнала, если только не была задана опция
65
Хотя пользователи могут посылать
3. Процесс может блокировать сигналы, когда выполняется часть кода, используя
Поскольку обработчики сигналов могут быть запущены почти в любое время, важно писать их так, чтобы они не делали никаких негарантированных предположений относительно остальной части программы, и чтобы они сами не изменяли ничего таким образом, что это могло бы запутать остальную программу, когда она возобновит выполнение.
Одним из наиболее важных моментов, за которым нужно следить, является модификация глобальных данных. Если только не делать этого аккуратно, возможно получение ситуации состязаний. Простейший способ обеспечить безопасность обновления глобальных данных — просто избегать его. Второй, и лучший, способ — это блокировка всех обработчиков сигналов, которые модифицируют определенные структуры данных, всякий раз, когда остальная часть кода модифицирует их, с тем, чтобы обеспечить одновременное манипулирование этими данными только одним сегментом кода одновременно.
Хотя обработчик сигнала может читать структуры данных, когда его прерывает другой читатель этих данных, все прочие комбинации являются небезопасными. Более безопасно обработчику сигнала модифицировать структуры данных, которые читает остальная часть программы, чем наоборот — обработчику сигналов читать структуры данных, которые остальная часть программы выполняет запись. Некоторые специализированные структуры данных спроектированы так, чтобы позволить параллельный доступ, но их описание выходит за круг тем, рассматриваемых в настоящей книге.
Если вам требуется доступ к глобальным данным из обработчика сигналов (что и делает большинство обработчиков), оставляйте структуры данных простыми. Хотя достаточно просто безопасно модифицировать отдельный элемент данных, такой как int, более сложные структуры обычно требуют блокировки сигналов. Любые глобальные переменные, которые могут быть модифицированы обработчиками сигналов, должны быть объявлены с ключевым словом
Другая вещь, с которой нужно соблюдать осторожность в обработчиках сигналов — это вызов других функций, потому что они тоже могут изменять глобальные данные! Библиотека С
Таблица 12.2. Реентерабельные функции
66
В табл. 12.2 перечислены функции, которые могут отсутствовать в некоторых, а может, даже во всех системах Linux. Мы включаем все функции, которые POSIX специфицирует в качестве безопасных для вызова из обработчиков сигналов.
abort | accept | access |
aio_error | aio_return | aio_suspend |
alarm | bind | cfgetispeed |
cfgetospeed | cfsetispeed | cfsetospeed |
chdir | chmod | chown |
close | connect | creat |
dup | dup2 | execle |
execve | _exit | fchmod |
fchown | fcntl | fdatasync |
fork | fpathconf | fstat |
fsync | getegid | geteuid |
getgid | getgroups | getpeername |
getpgrp | getpid | getppid |
getuid | kill | link |
listen | lseek | lstat |
mkdir | mkfifo | open |
pathconf | pause | pipe |
poll | posix_trace_event | pselect |
raise | read | readlink |
recv | recvfrom | recvmsg |
rename | rmdir | select |
sem_post | send | sendmsg |
sendto | setgid | setpgid |
setsid | setsockopt | setuid |
shutdown | sigaction | sigaddset |
sigdelset | sigemptyset | sigfillset |
sigismember | signal | sigpause |
sigpending | sigprocmask | sigqueue |
sigset | sigsuspend | sleep |
socket | socketpair | stat |
symlink | sysconf | tcdrain |
tcflow | tcflush | tcgetattr |
tcgetpgrp | tcsendbreak | tcsetattr |
tcsetpgrp | time | timer_getoverrun |
timer_gettime | timer_settime | times |
umask | uname | unlink |
utime | wait | wait3 |
wait4 | waitpid | write |
12.5.
Большинство системных демонов ведут журнальные файлы, записывая в них все, что они делают. Поскольку многие системы Unix месяцами работают без остановки, эти журнальные файлы могут стать достаточно большими. Простое периодическое удаление (или переименование) журнальных файлов — не самое хорошее решение, потому что демоны будут продолжать записывать в эти файлы, несмотря на их недоступность, а необходимость останавливать и запускать каждый демон для очистки журнальных файлов приводит к недоступности системы (хоть и на незначительное время). Общий способ для демонов справиться с упомянутой ситуацией — перехватывать
Logrotate (ftp://ftp.redhat.com/pub/redhat/code/logrotate/) — одна из программ, которая использует преимущество такого метода для выполнения безопасной ротации журналов.
Включение этой возможности у большинства демонов достаточно просто. Одним их наиболее легких подходов является использование глобальной переменной, которая индицирует необходимость повторного открытия журналов.
Затем обработчик сигнала