12.6.1. Очередность и порядок сигналов

12.6.1. Очередность и порядок сигналов

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

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

Сигналы реального времени всегда ставятся в очередь; каждый такой сигнал, посланный приложению, доставляется ему (если только приложение не прервано перед тем, как такой сигнал будет доставлен). Упорядочение сигналов реального времени также хорошо определено. Сигналы с меньшими номерами всегда доставляются перед сигналами с большими номерами, и когда множество сигналов с одинаковым номером поставлены в очередь, то они доставляются в порядке постановки. Порядок доставки сигналов, не относящихся к расширению реального времени, не определен, как и порядок доставки смеси сигналов реального времени и не относящихся к ним.

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

 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("Принятые сигналы: ");

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

65:   if (sigOrder[i] < SIGRTMIN)

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

67:   else

68:    printf(" SIGRTMIN + %d ", 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.