SIGACTION(2) | Руководство программиста Linux | SIGACTION(2) |
sigaction, rt_sigaction - получает и изменяет обработчик сигнала
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
sigaction(): _POSIX_C_SOURCE
siginfo_t: _POSIX_C_SOURCE >= 199309L
Системный вызов sigaction() используется для изменения выполняемого процессом действия при получении определённого сигнала (список сигналов смотрите в signal(7)).
В signum указывается сигнал; может принимать значение любого корректного сигнала за исключением SIGKILL и SIGSTOP.
Если значение act не равно NULL, то устанавливается новое действие для сигнала signum из act. Если значение oldact не равно NULL, то предыдущее действие записывается в oldact.
Структура sigaction определена следующим образом:
struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); };
Для некоторых архитектур используется union: не выполняйте назначение одновременно sa_handler и sa_sigaction.
Поле sa_restorer не предназначено для использования в приложении (в POSIX sa_restorer не определёно). Предназначение этого поля немного описано в sigreturn(2).
sa_handler указывает действие, которое должно быть связано с signum; может принимать значение SIG_DFL в качестве действия по умолчанию, SIG_IGN, чтобы игнорировать этот сигнал, или принимать указатель на функцию управления сигналом. Данная функция получает номер сигнала в качестве своего единственного аргумента.
Если в sa_flags указан SA_SIGINFO, то sa_sigaction (вместо sa_handler) задаёт функцию обработки сигнала signum. Эта функция имеет три параметра, которые описаны ниже.
В sa_mask задаётся маска сигналов, которые должны блокироваться (т.е. добавляется к маске сигналов нити, в которой вызывается обработчик сигнала) при выполнении обработчика сигнала. Также будет блокироваться и сигнал, вызвавший запуск обработчика, если только не был использован флаг SA_NODEFER.
В flag указывается набор флагов, которые изменяют поведение сигнала. Он формируется побитовым ИЛИ из следующих флагов:
Если в act.sa_flags указан флаг SA_SIGINFO, то адрес обработчика сигнала передаётся в поле act.sa_sigaction. Этот обработчик имеет три аргумента:
void handler(int sig, siginfo_t *info, void *ucontext) { ... }
Три параметра:
Тип данных siginfo_t представляется структурой со следующими полями:
siginfo_t { int si_signo; /* Номер сигнала */ int si_errno; /* Значение errno */ int si_code; /* Код сигнала */ int si_trapno; /* Номер ловушки, которую вызвал аппаратный сигнал (не используется на большинстве архитектур) */ pid_t si_pid; /* ID процесса, пославшего сигнал */ uid_t si_uid; /* ID реального пользователя процесса, пославшего сигнал */ int si_status; /* Выходное значение или номер сигнала */ clock_t si_utime; /* Использованное пользовательское время */ clock_t si_stime; /* Использованное системное время */ sigval_t si_value; /* Значение сигнала */ int si_int; /* Сигнал POSIX.1b */ void *si_ptr; /* Сигнал POSIX.1b */ int si_overrun; /* Счётчик переполнения таймера; таймеры POSIX.1b */ int si_timerid; /* ID таймера; таймеры POSIX.1b */ void *si_addr; /* Адрес памяти, приводящий к ошибке */ long si_band; /* Внутреннее событие (был int в glibc 2.3.2 и более ранних) */ int si_fd; /* Файловый дескриптор */ short si_addr_lsb; /* Наименее значимый бит адреса (начиная с Linux 2.6.32) */ void *si_lower; /* Нижняя граница при нарушении адреса (начиная с Linux 3.19) */ void *si_upper; /* Верхняя граница при нарушении адреса (начиная с Linux 3.19) */ int si_pkey; /* Ключа защиты в PTE, который привёл к ошибке (начиная с Linux 4.6) */ void *si_call_addr; /* Адрес инструкции системного вызова (начиная с Linux 3.5) */ int si_syscall; /* Количество попыток системного вызова (начиная с Linux 3.5) */ unsigned int si_arch; /* Архитектура пытавшегося системного вызова (начиная с Linux 3.5) */ }
Поля si_signo, si_errno и si_code определены для всех сигналов. (si_errno обычно не используется в Linux.) Оставшаяся часть структуры может представлять собой объединение, поэтому нужно читать только те поля, которые имеют смысл для заданного сигнала:
В поле si_code аргумента siginfo_t, передаваемого обработчику сигналов SA_SIGINFO содержится значение (не маска битов), определяющее причину отправки сигнала. При событии ptrace(2) в si_code будет содержаться SIGTRAP и событие ptrace в старшем байте:
(SIGTRAP | PTRACE_EVENT_foo << 8).
Не события не ptrace(2) значения, которые могут появиться в si_code, описаны в конце этого раздела. Начиная с glibc 2.20, определения большинства этих символов доступны из <signal.h> при определении макросов тестирования свойств (до включения какого-либо заголовочного файла) следующим образом:
Определения символов констант TRAP_* предоставляются только в первых двух случаях. До glibc 2.20 для получения этих символов макросы тестирования свойств были не нужны.
Для обычного сигнала в следующей таблице приведены значения, которые могут быть в si_code для любого сигнала, и причина возникновения сигнала:
Следующие значения могут присутствовать в si_code для сигнала SIGILL:
Следующие значения могут присутствовать в si_code для сигнала SIGFPE:
Следующие значения могут присутствовать в si_code для сигнала SIGSEGV:
Следующие значения могут присутствовать в si_code для сигнала SIGBUS:
Следующие значения могут присутствовать в si_code для сигнала SIGTRAP:
Следующие значения могут присутствовать в si_code для сигнала SIGCHLD:
Следующие значения могут присутствовать в si_code для сигнала SIGIO/SIGPOLL:
Следующее значение может присутствовать в si_code для сигнала SIGSYS:
При успешном выполнении sigaction() возвращается 0; при ошибке возвращается -1, а в errno содержится код ошибки.
POSIX.1-2001, POSIX.1-2008, SVr4.
Потомок, созданный с помощью fork(2), наследует реакцию на сигналы от своего родителя. При execve(2) реакция на сигналы устанавливается в значение по умолчанию; реакция на игнорируемые сигналы не изменяется.
В соответствии с POSIX поведение процесса после игнорирования сигнала SIGFPE, SIGILL или SIGSEGV не определено, если эти сигналы не были посланы при помощи функций kill(2) или raise(3). Деление целого числа на ноль имеет непредсказуемый результат. В некоторых архитектурах это приводит к появлению сигнала SIGFPE. (Также, деление самого большого по модулю отрицательного числа на -1 тоже может приводить к SIGFPE.) Игнорирование этого сигнала может привести к появлению бесконечного цикла.
POSIX.1-1990 запрещает установку действия для сигнала SIGCHLD в SIG_IGN. В POSIX.1-2001 и новых версиях стандарта допускается такая возможность, поэтому игнорирование SIGCHLD можно использовать для недопущения создания зомби (смотрите wait(2)). Тем не менее, поведение BSD и System V по игнорированию SIGCHLD различается, поэтому есть только один переносимый способ убедиться, что завершившийся потомок не стал зомби — поймать сигнал SIGCHLD и выполнить wait(2) или подобный вызов.
В POSIX.1-1990 указан только SA_NOCLDSTOP. В POSIX.1-2001 добавлены SA_NOCLDSTOP, SA_NOCLDWAIT, SA_NODEFER, SA_ONSTACK, SA_RESETHAND, SA_RESTART и SA_SIGINFO. Использование в приложениях последних значений в sa_flags может оказаться сложнее перенести на старые реализации UNIX.
Флаг SA_RESETHAND совместим с одноимённым флагом из SVr4.
Флаг SA_NODEFER совместим с одноименным флагом SVr4 в ядре версии 1.3.9 и более поздних. В старых выпусках ядра Linux позволяли принимать и обрабатывать любые сигналы, а не только те, обработка которых уже задана (на деле это приводит к игнорированию установок sa_mask).
Для получения адреса текущего обработчика сигнала можно использовать вызов sigaction(), указав NULL в качестве значения второго аргумента. Этот вызов можно также использовать для проверки доступности этого типа сигнала в конкретной системе, вызвав его с вторым и третьим аргументами, равными NULL.
Невозможно заблокировать сигналы SIGKILL или SIGSTOP (указав их в sa_mask). Попытки это сделать будут просто игнорироваться.
Подробная информация о работе с наборами сигналов есть на странице sigsetops(3).
Список функций безопасных асинхронных сигналов, которые можно не опасаясь вызывать из обработчика сигналов, смотрите в signal-safety(7).
Обёрточная функция glibc для sigaction() выдаёт ошибку (EINVAL) при попытках изменить обработчики двух сигналов реального времени, которые используются внутри реализации NPTL. Подробности смотрите в nptl(7).
На архитектурах, где переход от сигнала (signal trampoline) располагается в библиотеке C, обёрточная функция glibc для sigaction() помещает адрес кода перехода в поле act.sa_restorer и изменяет флаг SA_RESTORER в поле act.sa_flags. Смотрите sigreturn(2).
Первоначально, системный вызов Linux назывался sigaction(). Однако, с добавлением сигналов реального времени в Linux 2.2, 32-битный аргумент sigset_t неизменяемого размера, поддерживаемый этим системным вызовом, не мог больше использоваться. В результате был добавлен новый системный вызов rt_sigaction() с увеличенным типом sigset_t. У нового системного вызова появился четвёртый аргумент, size_t sigsetsize, в котором указывается размер (в байтах) наборов сигналов act.sa_mask и oldact.sa_mask. В настоящее время значение этого аргумента должно быть равно sizeof(sigset_t) (иначе возникает ошибка EINVAL). Обёрточная функция glibc sigaction() скрывает это и вызывает rt_sigaction(), если он есть в ядре.
До появления SA_SIGINFO также было возможно получить дополнительную информацию о сигнале. Для этого в обработчике сигнала sa_handler заполняется второй параметр типа struct sigcontext, который повторяет структуру, передаваемую в поле uc_mcontext структуры ucontext, которая передаётся (через указатель) в третьем аргументе обработчика sa_sigaction. Смотрите соответствующий исходный код ядра Linux. В настоящее время этот механизм устарел.
В ядрах по версию 2.6.13 включительно, указание SA_NODEFER в sa_flags предотвращает доставку сигнала не только из маскируемого при выполнении обработчика, но также сигналов, указанных в sa_mask. Этот дефект исправлен в ядре 2.6.14.
Смотрите в mprotect(2).
kill(1), kill(2), pause(2), restart_syscall(2), seccomp(2) sigaltstack(2), signal(2), signalfd(2), sigpending(2), sigprocmask(2), sigreturn(2), sigsuspend(2), wait(2), killpg(3), raise(3), siginterrupt(3), sigqueue(3), sigsetops(3), sigvec(3), core(5), signal(7)
2019-03-06 | Linux |