Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

 5: #include <stdio.h>

 6: #include <unistd.h>

 7:

 8: #ifndef SI_TKILL

 9: #define SI_TKILL -6

10: #endif

11:

12: void handler(int signo, siginfo_t *info, void *f ) {

13: static int count = 0;

14:

15: printf("перехвачен сигнал, отправленный ");

16: switch(info->si_code) {

17: case SI_USER:

18: printf("kill\n"); break;

19: case SI_QUEUE:

20: printf("sigqueue\n"); break;

21: case SI_TKILL:

22: printf("tkill
или raise\n"); break;

23: case CLD_EXITED:

24: printf ("ядро сообщает, что дочерний процесс завершен\n"); exit(0);

25: }

26:

27: if (++count == 4) exit(1);

28: }

29:

30: int main {

31: struct sigaction act;

32: union sigval val;

33: pid_t pid = getpid;

34:

35: val.sival_int = 1234;

36:

37: act.sa_sigaction = handler;

38: sigemptyset(&act.sa_mask);

39: act.sa_flags = SA_SIGINFO;

40: sigaction(SIGCHLD, &act, NULL);

41:

42: kill(pid, SIGCHLD);

43: sigqueue(pid, SIGCHLD, val);

44: raise(SIGCHLD);

45:

46: /* Чтобы получить SIGCHLD от ядра, мы создаем дочерний процесс

47: и немедленно завершаем его. Обработчик сигнала выйдет после

48: получения сигнала от ядра, поэтому мы просто засыпаем

49: на время и позволяем программе прерваться подобным образом. */

50:

51: if (!fork) exit(0);

52: sleep(60);

53:

54: return 0;

55: }

Если

si_code
равно
SI_USER
,
SI_QUEUE
или
SI_TKILL
, то доступны два дополнительных члена
siginfo_t
:
si_pid
и
si_uid
, которые представляют идентификатор процесса, пославшего сигнал и действительный идентификатор пользователя этого процесса.

Когда ядром посылается

SIGCHLD
, доступны члены
si_pid
,
si_status
,
si_utime
и
si_stime
. Первый из них,
si_pid
, задает идентификатор процесса, состояние которого изменилось [72] . Информация о новом состоянии доступна как в
si_code
(как показано в табл. 12.3) и в
si_status
, что
идентично целому значению состояния, возвращаемому семейством функций
wait
.

72

Вспомните, что

SIGCHLD
посылается не только при завершении дочернего процесса, но и при его приостановке или возобновлении работы.

Последние два члена,

si_utime
и
si_stime
, определяют период времени, которое потрачено дочерним приложением на работу в пользовательском режиме и в режиме ядра, соответственно (это подобно тому, что возвращают вызовы
wait3
и
wait4
в структуре
struct rusage
). Это время измеряется в тиках часов, заданных целым числом. Количество тиков в секунду задает макрос
_SC_CLK_TCK
, определенный в
<sysconf.h>
.

SIGSEGV
,
SIGBUS
,
SIGILL
и
SIGFPE
— все они представляют
si_addr
, специфицирующий адрес, который вызвал сбой, описанный
si code
.

Ниже приведен простой пример проверки контекста сигнала. Он устанавливает обработчик сигнала для

SIGSEGV
, который печатает контекст сигнала и прерывает процесс. Нарушение сегментации генерируется попыткой обращения к
NULL
.

 1: /* catch-segv.c */

 2:

 3: #include <sys/signal.h>

 4: #include <stdlib.h>

 5: #include <stdio.h>

 6:

 7: void handler(int signo, siginfo_t *info, void *f) {

 8: printf("перехват");

 9: if (info->si_signo == SIGSEGV)

10: printf("segv accessing %p", info->si_addr);

11: if (info->si_code == SEGV_MAPERR)

12: printf("SEGV_MAPERR");

13: printf("\n");

14:

15: exit(1);

16: }

17:

18: int main {

19: struct sigactin act;

20:

21: act.sa_sigaction = handler;

22: sigemptyset(&act.sa_mask);

23: act.sa_flags = SA_SIGINFO;

24: sigaction(SIGSEGV, &act, NULL);

25:

26: *((int *)NULL) = 1 ;

27:

28: return 0;

29: }

12.7.2. Отправка данных с сигналом

Механизм

siginfo_t
также позволяет сигналам, которые посылают программы, присоединять к себе один элемент данных (этот элемент может быть указателем, что позволяет неявно передавать любой необходимый объем данных). Чтобы отправить данные, используется
union sigval
.

Поделиться с друзьями: