#include <signal.h> #include <time.h> int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
Link with -lrt.
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
timer_create(): _POSIX_C_SOURCE >= 199309L
The clockid argument specifies the clock that the new timer uses to measure time. It can be specified as one of the following values:
As well as the above values, clockid can be specified as the clockid returned by a call to clock_getcpuclockid(3) or pthread_getcpuclockid(3).
The evp argument points to a sigevent structure that specifies how the caller should be notified when the timer expires. For the definition and general details of this structure, see sigevent(7).
The evp.sigev_notify field can have the following values:
Specifying evp as NULL is equivalent to specifying a pointer to a sigevent structure in which sigev_notify is SIGEV_SIGNAL, sigev_signo is SIGALRM, and sigev_value.sival_int is the timer ID.
Timers are not inherited by the child of a fork(2), and are disarmed and deleted during an execve(2).
The kernel preallocates a "queued real-time signal" for each timer created using timer_create(). Consequently, the number of timers is limited by the RLIMIT_SIGPENDING resource limit (see setrlimit(2)).
The timers created by timer_create() are commonly known as "POSIX (interval) timers". The POSIX timers API consists of the following interfaces:
Part of the implementation of the POSIX timers API is provided by glibc. In particular:
The POSIX timers system calls first appeared in Linux 2.6. Prior to this, glibc provided an incomplete userspace implementation (CLOCK_REALTIME timers only) using POSIX threads, and current glibc falls back to this implementation on systems running pre-2.6 Linux kernels.
In the following example run, the program sleeps for 1 second, after creating a timer that has a frequency of 100 nanoseconds. By the time the signal is unblocked and delivered, there have been around ten million overruns.
$ ./a.out 1 10 Establishing handler for signal 34 Blocking signal 34 timer ID is 0x804c008 Sleeping for 1 seconds Unblocking signal 34 Caught signal 34 sival_ptr = 0xbfb174f4; *sival_ptr = 0x804c008 overrun count = 10004886
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <signal.h> #include <time.h> #define CLOCKID CLOCK_REALTIME #define SIG SIGRTMIN #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void print_siginfo(siginfo_t *si) { timer_t *tidp; int or; tidp = si->si_value.sival_ptr; printf(" sival_ptr = %p; ", si->si_value.sival_ptr); printf(" *sival_ptr = 0x%lx\n", (long) *tidp); or = timer_getoverrun(*tidp); if (or == -1) errExit("timer_getoverrun"); else printf(" overrun count = %d\n", or); } static void handler(int sig, siginfo_t *si, void *uc) { /* Note: calling printf() from a signal handler is not strictly correct, since printf() is not async-signal-safe; see signal(7) */ printf("Caught signal %d\n", sig); print_siginfo(si); signal(sig, SIG_IGN); } int main(int argc, char *argv[]) { timer_t timerid; struct sigevent sev; struct itimerspec its; long long freq_nanosecs; sigset_t mask; struct sigaction sa; if (argc != 3) { fprintf(stderr, "Usage: %s <sleep-secs> <freq-nanosecs>\n", argv[0]); exit(EXIT_FAILURE); } /* Establish handler for timer signal */ printf("Establishing handler for signal %d\n", SIG); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); if (sigaction(SIG, &sa, NULL) == -1) errExit("sigaction"); /* Block timer signal temporarily */ printf("Blocking signal %d\n", SIG); sigemptyset(&mask); sigaddset(&mask, SIG); if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) errExit("sigprocmask"); /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCKID, &sev, &timerid) == -1) errExit("timer_create"); printf("timer ID is 0x%lx\n", (long) timerid); /* Start the timer */ freq_nanosecs = atoll(argv[2]); its.it_value.tv_sec = freq_nanosecs / 1000000000; its.it_value.tv_nsec = freq_nanosecs % 1000000000; its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; if (timer_settime(timerid, 0, &its, NULL) == -1) errExit("timer_settime"); /* Sleep for a while; meanwhile, the timer may expire multiple times */ printf("Sleeping for %d seconds\n", atoi(argv[1])); sleep(atoi(argv[1])); /* Unlock the timer signal, so that timer notification can be delivered */ printf("Unblocking signal %d\n", SIG); if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) errExit("sigprocmask"); exit(EXIT_SUCCESS); }