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

ЖАНРЫ

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

Троан Эрик В.

Шрифт:

Ниже показан пример кода, иллюстрирующий постановку сигналов в очередь и их упорядочивание.

 1: /* queued.с */

 2:

 3: /* получить определение strsignal из string.h */

 4: #define _GNU_SOURCE1

 5:

 6: #include <sys/signal.h>

 7: #include <stdlib.h>

 8: #include <stdio.h>

 9: #include <string.h>

10: #include <unistd.h>

11:

12: /*
Глобальные переменные для построения списка сигналов */

13: int nextSig = 0;

14: int sigOrder[10];

15:

16: /* Перехватить сигнал и записать, что он был обработан */

17: void handler(int signo) {

18: sigOrder[nextSig++] = signo;

19: }

20:

21: int main {

22: sigset_t mask;

23: sigset_t oldMask;

24: struct sigaction act;

25: int i;

26:

27: /* Обрабатываемые в программе сигналы */

28: sigemptyset(&mask);

29: sigaddset(&mask, SIGRTMIN);

30: sigaddset(&mask, SIGRTMIN+1);

31: sigaddset(&mask, SIGUSR1);

32:

33: /* Отправить сигнал handler и сохранять их блокированными,

34: чтобы handler был сконфигурирован во избежание

35: состязаний при манипулировании глобальными переменными */

36: act.sa_handler = handler;

37: act.sa_mask = mask;

38: act.sa_flags = 0;

39:

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

41: sigaction(SIGRTMIN+1, &act, NULL);

42: sigaction(SIGUSR1, &act, NULL);

43:

44: /* Блокировать сигналы, с которыми мы работаем, чтобы

45: была видна очередность и порядок */

46: sigprocmask(SIG_BLOCK, &mask, &oldMask);

47:

48: /* Генерировать сигналы */

49: raise(SIGRTMIN+1);

50: raise(SIGRTMIN);

51: raise(SIGRTMIN);

52: raise(SIGRTMIN+1);

53: raise(SIGRTMIN);

54: raise(SIGUSR1);

55: raise(SIGUSR1);

56:

57: /* Разрешить доставку этих сигналов. Все они будут доставлены

58: прямо перед возвратом этого вызова (для Linux; это

59: НЕПЕРЕНОСИМОЕ поведение). */

60: sigprocmask(SIG_SETMASK, &oldMask, NULL);

61:

62: /* Отобразить упорядоченный список перехваченных сигналов */

63: printf("Принятые сигналы:\n");

64: for (i = 0; i < nextSig; i++)

65: if (sigOrder[i] < SIGRTMIN)

66: printf("\t%s\n", strsignal(sigOrder[i]));

67: else

68: printf("\tSIGRTMIN + %d\n", sigOrder[i] - SIGRTMIN);

69:

70: return 0;

71: }

Эта

программа посылает себе некоторое количество сигналов и выводит на дисплей порядок их получения. Когда сигналы отправляются, она блокирует их, чтобы предотвратить немедленную доставку. Также она блокирует сигналы всякий раз, когда вызывается обработчик, устанавливая значение члена
sa_mask
структуры
struct sigaction
при настройке обработчика для каждого сигнала. Это предотвращает возможное состояние состязаний при обращении к глобальным переменным
nextSig
и
sigOrder
изнутри обработчика.

Запуск этой программы выдаст показанные ниже результаты.

Принятые сигналы:

User defined signal1

SIGRTMIN + 0

SIGRTMIN + 0

SIGRTMIN + 0

SIGRTMIN + 1

SIGRTMIN + 1

Это показывает, что все сигналы реального времени были доставлены, в то же время, был доставлен только один экземпляр сигнала

SIGUSR1
. Вы также видите изменение порядка сигналов реального времени — все сигналы
SIGRTMIN
были доставлены перед
SIGRTMIN + 1
.

12.7. Дополнительные сведения о сигналах

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

SIGSEGV
), или же иметь возможность включить данные в сигналы, генерируемые приложением. Расширение реального времени Real Time Signals позволяет решить обе эти задачи.

12.7.1. Получение контекста сигнала

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

siginfo_t
, предоставляющий контекст сигнала, и указатель на
void*
, который может быть использован некоторыми низкоуровневыми системными библиотеками [69] . Вот как выглядит полный прототип такого обработчика.

68

До появления стандарта POSIX приложение могло обращаться к

struct sigcontext
за информацией того же рода, что теперь представляет
siginfo_t
, и термин "контекст" остался от этой старой реализации.

69

Этот третий параметр на самом деле указывает на структуру

struct ucontext
, которая позволяет процессам выполнять полное переключение контекстов в пользовательском пространстве. Данные вопросы выходят за пределы тем, рассматриваемых в настоящей книге, но это хорошо документировано в Single Unix Specification.

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