#include #include #include #include #include #include #include #include static int handler_run; static const union sigval my_sigval = { .sival_int = 42, }; #define bail(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0); static void handler(int sig, siginfo_t *si, void *notused) { assert(si->si_code == SI_TIMER); assert(si->si_ptr == my_sigval.sival_ptr); /* Succeeds */ assert(si->si_int == my_sigval.sival_int); /* Succeeds */ /* This should run only once */ assert(handler_run == 0); handler_run++; } int main(void) { struct signalfd_siginfo fdsi; struct sigaction newact; struct itimerspec its; struct sigevent sev; timer_t timerid; sigset_t mask; ssize_t s; int sfd; newact.sa_flags = SA_SIGINFO | SA_RESETHAND; newact.sa_sigaction = handler; sigemptyset(&newact.sa_mask); if (sigaction(SIGRTMIN, &newact, NULL) == -1) bail("sigaction"); memset(&sev, 0, sizeof(sev)); sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value = my_sigval; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) bail("timer_create"); /* Timer expires just once */ its.it_value.tv_sec = 0; its.it_value.tv_nsec = 100; its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 0; /* Arm timer */ if (timer_settime(timerid, 0, &its, NULL) == -1) bail("timer_settime"); /* Wait for timer to expire, which executes the handler */ while (!handler_run) usleep(100000); /* Inhibit default SIGRTMIN handling */ sigemptyset(&mask); sigaddset(&mask, SIGRTMIN); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) bail("sigprocmask"); sfd = signalfd(-1, &mask, 0); if (sfd == -1) bail("signalfd"); /* Re-arm timer */ if (timer_settime(timerid, 0, &its, NULL) == -1) bail("timer_settime"); /* Block until timer expiration */ s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); if (s != sizeof(struct signalfd_siginfo)) bail("read"); assert(fdsi.ssi_code == SI_TIMER); assert(fdsi.ssi_ptr == (unsigned long)my_sigval.sival_ptr); /* Succeeds */ assert(fdsi.ssi_int == my_sigval.sival_int); /* Fails */ return EXIT_SUCCESS; }