Сигналы

Программные прерывания, предоставляющие механизм для обработки асинхронных событий. Такие события могут инициироваться пользователем (нажатие клавиш ctrl+c) или возникать вследствие действий в программе или ядре.

Отличительная особенность сигналов состоит в том, что они появляются асинхронно, и обработка их производится тоже асинхронно. Могут быть написаны функции обработки сигналов, эти функции регистрируются процессом в ядре операционной системы, а операционная система инициирует выполнение этих функций при получении соответствующих сигналов в соответствии с установленными правилами обработки.

Сигналы имеют определенный жизненный цикл:

1) состояние, связанное с генерированием (отправлением, поднятием) сигнала:

generate //

send // смысл: сигнал появился

raise //

2) состояние хранения (store) – ядро операционной системы хранит его до тех пор, пока не появляется условие для доставки сигнала. И после того, как соответствующие условия создаются, ядро инициирует (обрабатывает) поступивший сигнал.

Ядро может выполнить 3 действия связанные с обработкой сигнала:

1. Игнорирование сигнала. //сигнал направлен процессу, но действий нету. НО есть ряд сигналов, которые нельзя игнорировать:

SIGKILL //связаны с остановкой или «убийством» процесса

SIGSTOP

2. Выполнить действие по умолчанию.

Для всех сигналов предусмотрены действия, которые выполняются по умолчанию. Это или завершение процесса, или может быть действие игнорировать сигнал, захватить и обработать сигнал. Процесс прерывается, и запускается функция обработчик

3. Установление собственного обработчика

Написать функцию обработчик и зарегистрировать её. Но есть некоторые сигналы, которые нельзя описать самостоятельно. Ядро приостанавливает текущее выполнение процесса, и переходит к выполнению ранее зарегистрированной функции. После завершения выполнения функции ядро продолжает обрабатывать остановленный исходный процесс.

Все сигналы имеют символическое имя. Все символические имена описаны в <signal.h> и начинаются с префикса SIG. Сигналы имеют номера (целочисленные). Общее число сигналов системы порядка 30.

SIGKILL завершить мгновенно, отправляется системным вызовом kill() завершить процесс
SIGSTOP остановить сигнал остановить процесс
SIGALARM отправляется процессу при завершении времени установленного функцией alarm(). завершить процесс
SIGHUP ядро оправляет лидеру сеанса, когда терминал сеанса отключается. Также этот сигнал отправляется всем процессам приоритетной группы, когда лидер сеанса завершается (пользователь выходит из системы) завершить процесс
SIGINT отправляется всем процессам приоритетной группы, при нажатии CTRL+C. Можно написать обработчик. завершить процесс
SIGUSR1 Используются только пользователями. могут использоваться для взаимодействия с процессом демоном. Можно написать обработчик завершить процесс
SIGUSR2

Методика асинхронного механизма получения и обработки сигнала: обработка сигнала производится во время приостановки самого процесса.

Системный вызов установки обработчика на сигнал

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signo, sighandler_t handler)

Позволяет зарегистрировать обработчик для сигнала, указанного в качестве первого аргумента. Второй аргумент - адрес функции обработчика. В качестве второго аргумента могут использоваться также:

SIG_DFL //восстановить поведение по умолчанию для сигнала signo.

SIG_IGN //игнорировать сигнал, указанный параметром signo

Функция signal() возвращает предыдущее поведение сигнала, которое может принимать вид указателя на обработчик сигнала, SIG_DFL или SIG_IGN. При ошибке возвращается значение SIG_ERP. Переменная errno не устанавливается.

Функция ожидания:

#include <unistd.h>

int pause (void);

выполнение процесса приостанавливается, пока не будет получен сигнал, допускающий либо обработку, либо завершение процесса. Функция возвращает значение только тогда, когда получен сигнал, который перехватывается, и возвращается -1, а переменная errno = EINTR.

#include <signal.h>

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

static void sig_hand(int signo)

{signal (signo, sig_hand);

if (signo == SIGINT) printf(“получен сигнал SIGINT ”);

else if (signo == SIGTERM) printf(“ получен сигнал SIGTERM”)

else {printf(“неописанный сигнал”); exit(EXIT_FAILURE);}

exit(EXIT_SUCCESS);}

int main()

{

if (signal (SIGINT, sig_hand) == SIG_ERR) {printf(“ошибка SIGINT”);

exit(-1);}

if (signal(SIGTERM, sig_hand) == SIR_ERR) {printf(“ошибка SIGTERM”);

exit(-2);}

if (signal(SIGHUP, SIG_IGN) == SIR_ERR) {printf(“невозможно игнорировать SIGHUP”);

exit(-3);}

for (;;) pause();

}

Когда порождается новый процесс, для него устанавливается поведение всех сигналов по умолчанию, если только родительский процесс не игнорирует какие-то сигналы. Таким образом, новый процесс выполняет действие по умолчанию для всех сигналов захватываемых предком, а все прочие сигналы не вызывают действий

#include <signal.h> <stdlib.h> <stdio.h> <unistd.h>

if (signal(SIGINT, SIG_IGN)!= SIGIGN)

{if (signal(SIGINT, sigint_handler) == SIG_ERR) {…}}

Свойство игнорирования сигналов порожденным процессом, заимствованное у родительского процесса, можно использовать для создания фоновых процессов. Для этого перед тем как фоновый процесс запускается для сигналов SIGINT & SIGQUIT, устанавливается игнорирование этих сигналов. Поэтому процессы, которые производят перехват этих сигналов перед установкой обработчика проверяют, не было ли установлено игнорирование для этих сигналов.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: