Для каждого процесса ядро хранит специальную маску, которая определяет те сигналы, которые будут временно заблокированы и необработаны.
Если в процесс отправляется заблокированный сигнал, то доставка этого сигнала откладывается до тех пор, пока он не будет разблокирован путем удаления из сигнальной маски.
Как же нам определить эту чудо-маску и замутить пару сигналов?) Использовать системный вызов sigprocmask():
#include <signal.h>
int sigprogmask(int how, const sigset_t *set, sigset_t *oldset);
Аргумент how определяет то, каким образом набор сигналов, передаваемый в set, изменит текущую маску процесса:
1. SIG_BLOCK — сигналы, включенные set, добавляются в сигнальную маску. Другими словами, блокируемые сигналы остаются таковыми, а новые добавляются к ним;
2. SIG_UNBLOCK — сигналы, включенные set, исключаются из сигнальной маски;
3. SIG_SETMASK — сигналы, включенные set, переопределяют текущую маску. Сигналы, не включённые в новое множество, больше не блокируются;
Если аргумент oldset не равен NULL, то он указывает на переменную типа sigset_t, в которую записывается текущее значение сигнальной маски (до изменения).
Если мы хотим через oldset получить сигнальную маску без каких-то изменений, можно установить значение NULL для аргумента set, в этом случае аргумент how будет проигнорирован.
Ну все, давайте, ближе к делу, ближе к коду. Сейчас используем вообще все наши знания по сигналам: напишем перехватчик, отправим сигнал самому себе, определим маску и посмотрим на результат:
#include <signal.h>
#include <unistd.h>
void handler (int num) {
write(STDOUT_FILENO, "I won't die!\n", 13);
}
int main() {
signal(SIGINT, handler);
sigset_t blockSet, prevMask;
sigemptyset(&blockSet);
sigaddset(&blockSet, SIGINT);
sigprocmask(SIG_BLOCK, &blockSet, &prevMask);
raise(SIGINT);
return 0;
}
Теперь скомпилим и запустим прогу:
$ gcc -o prog main.c
$ ./prog
И что... Бам, никакого вывода мы не увидим - маска успешно отработала.
А теперь го еще прикол. Помните, ранее речь заходила о том, что отправленные сигналы не отменяются, а откладываются - как только мы уберем его из маски, процесс его примет и обработает.
Проверить мы это сможем, если добавим следующий код после вызова "raise(SIGINT);":
sleep(5);
sigprocmask(SIG_SETMASK, &prevMask, NULL);
Ждем 5 сек и наблюдаем лог:
$ ./prog
I won't die!
Теперь пару слов про сигналы: SIGKILL и SIGSTOP. Их мы игнорировать не можем, УВЫ и АХ. Если мы попытаемся заблокировать эти сигналы, функция sigprocmask() ошибку не выдаст, но и желаемого результата мы также не получим.
Для того чтобы добавить все сигналы в маску, кроме SIGKILL и SIGSTOP, мы можем использовать следующий вызов:
sigfillset(&blockSet);
LinuxCamp