Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
Оба случая относятся к состоянию гонки. Одним решением для этих проблем является как можно большее упрощение обработчиков сигналов. Это можно сделать, создав флаговые переменные, указывающие на появление сигнала. Обработчик сигнала устанавливает переменную в true и возвращается. Затем основная логика проверяет флаговую переменную в стратегических местах:
int sig_int_flag = 0; /* обработчик сигнала устанавливает в true */void int_handler(int signum) { sig_int_flag = 1;}int main(int argc, char **argv) { bsd_signal(SIGINT, int_handler); /* ...программа продолжается... */ if (sig_int_flag) { /* возник SIGINT, обработать его */ } /* ...оставшаяся логика... */}(Обратите внимание, что эта стратегия уменьшает окно уязвимости, но не устраняет его).
Стандарт С вводит специальный тип —
sig_atomic_tintsig_atomic_tНаличие особого типа является лишь частью истории. Переменные
sig_atomic_tvolatilevolatile sig_atomic_t sig_int_flag = 0; /* обработчик сигнала устанавливает в true *//* ...оставшаяся часть кода как раньше... */Ключевое слово
volatileСтруктурирование приложения исключительно вокруг переменных
sig_atomic_t10.4.6. Дополнительные предостережения
Стандарт POSIX предусматривает для обработчиков сигналов несколько предостережений:
• Что случается, когда возвращаются обработчики для
SIGFPESIGILLSIGSEGV• Если обработчик был вызван в результате вызова
abort()raise()kill()raise()abort()abort()kill()sigaction()• Обработчики сигналов могут вызвать лишь функции из табл. 10.2. В частности, они должны избегать функций
<stdio.h><stdio.h><stdio.h>Список в табл. 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() |