./t_sigwaitinfo: PID is 3837
./t_sigwaitinfo: signals blocked
./t_sigwaitinfo: about to delay 60 seconds
[1] 3837
$ ./t_sigqueue 3837 43 100
./t_sigqueue: PID is 3839, UID is 1000
$ ./t_sigqueue 3837 42 200
./t_sigqueue: PID is 3840, UID is 1000
Со временем программа завершает период сна — и цикл с функцией sigwaitinfo() принимает поставленные в очередь сигналы. (На экране приглашения оболочки перемешаны с выводом программы, так как программа t_sigwaitinfo распечатывает вывод из фонового режима). Как и в случае с сигналами реального времени, перехваченными обработчиком, мы видим, что сигналы доставляются в порядке увеличения их номера, а также что структура siginfo_t, передаваемая обработчику сигнала, позволяет нам получить идентификатор процесса и идентификатор пользователя процесса, пославшего сигнал:
$ ./t_sigwaitinfo: finished delay
got signal: 42
si_signo=42, si_code=–1 (SI_QUEUE), si_value=200
si_pid=3840, si_uid=1000
got signal: 43
si_signo=43, si_code=–1 (SI_QUEUE), si_value=100
si_pid=3839, si_uid=1000
Мы продолжаем, используя команду оболочки kill для отправки сигнала в процесс. В этот раз мы увидим, что полю si_code присвоено значение SI_USER (вместо SI_QUEUE):
$ echo $$
3744
$ kill — USR1 3837
$ got signal: 10
si_signo=10, si_code=0 (SI_USER), si_value=100
si_pid=3744, si_uid=1000
$ kill %1
$
[1]+ Done./t_sigwaitinfo 60
В выводе для принятого сигнала SIGUSR1 мы видим, что полю si_value присвоено значение 100. Это то значение, с каким данное поле было инициализировано предшествующим сигналом, отправленным с помощью функции sigqueue(). Ранее отмечалось, что поле si_value содержит валидную информацию только для сигналов, посланных с помощью функции sigqueue().
Листинг 22.6. Синхронное ожидание сигналов с sigwaitinfo()
signals/t_sigwaitinfo.c
#define _GNU_SOURCE
#include
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int sig;
siginfo_t si;
sigset_t allSigs;
if (argc > 1 && strcmp(argv[1], "-help") == 0)
usageErr("%s [delay-secs]\n", argv[0]);
printf("%s: PID is %ld\n", argv[0], (long) getpid());
/* Блокировать все сигналы (исключая SIGKILL и SIGSTOP) */
sigfillset(&allSigs);
if (sigprocmask(SIG_SETMASK, &allSigs, NULL) == –1)
errExit("sigprocmask");
printf("%s: signals blocked\n", argv[0]);
if (argc > 1) {
/* Пауза для того, чтобы сигналы могли быть отправлены нам */
printf("%s: about to delay %s seconds\n", argv[0], argv[1]);
sleep(getInt(argv[1], GN_GT_0, "delay-secs"));
printf("%s: finished delay\n", argv[0]);
}
for (;;) { /* Получать сигналы до SIGINT (^C) или SIGTERM */
sig = sigwaitinfo(&allSigs, &si);
if (sig == –1)
errExit("sigwaitinfo");
if (sig == SIGINT || sig == SIGTERM)
exit(EXIT_SUCCESS);
printf("got signal: %d (%s)\n", sig, strsignal(sig));
printf(" si_signo=%d, si_code=%d (%s), si_value=%d\n",
si.si_signo, si.si_code,
(si.si_code == SI_USER)? "SI_USER":
(si.si_code == SI_QUEUE)? "SI_QUEUE": "other",
si.si_value.sival_int);
printf(" si_pid=%ld, si_uid=%ld\n",
(long) si.si_pid, (long) si.si_uid);
}
}
signals/t_sigwaitinfo.c
Системный вызов sigtimedwait() — это вариация функции sigwaitinfo(). Единственное отличие заключается в том, что функция sigtimedwait() позволяет ограничить время ожидания.
#define _POSIX_C_SOURCE 199309
#include
int sigtimedwait(const sigset_t *
const struct timespec *
Возвращает номер доставленного сигнала при успешном завершении или –1 при ошибке или тайм-ауте (EAGAIN)
Аргумент timeout устанавливает максимальное количество времени, на протяжении которого функция sigtimedwait() будет ожидать сигнал. Этот аргумент — это указатель на структуру следующего типа:
struct timespec {
time_t tv_sec; /* Секунды ('time_t' целочисленный тип) */
long tv_nsec; /* Наносекунды */
};