$RodHat_
Syscall reference · Events

timerfd_create(2)

Create a timer that reports expirations through a readable file descriptor.

Since
Linux 2.6.25check your kernel →
glibc
glibc 2.8
System
Linux
Man page
timerfd_create(2)

Synopsis

#include <sys/timerfd.h>

int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags,
                    const struct itimerspec *new_value,
                    struct itimerspec *_Nullable old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);

Rod's take

SIGALRM plus setitimer means a handler firing at some arbitrary point in your code to flip a global you'll check later. Garbage, and always was. timerfd makes the timer a file descriptor: it goes readable when it fires, and read() hands back a 64-bit count of expirations, so a slow loop finds out it missed three ticks instead of silently losing them. CLOCK_MONOTONIC for intervals; CLOCK_REALTIME only for wall-clock deadlines, with TFD_TIMER_ABSTIME. Then drop it in epoll next to everything else and stop thinking about signals.

Flags and arguments that matter

NameWhat it does
CLOCK_MONOTONICNonsettable monotonic clock; the right choice for intervals.
CLOCK_REALTIMESettable wall clock; use with TFD_TIMER_ABSTIME for wall-clock deadlines.
CLOCK_BOOTTIMELinux 3.15Like CLOCK_MONOTONIC but keeps counting while the system is suspended.
CLOCK_REALTIME_ALARM / CLOCK_BOOTTIME_ALARMLinux 3.11Wake the system from suspend; setting requires CAP_WAKE_ALARM.
TFD_NONBLOCKLinux 2.6.27Set O_NONBLOCK on the new descriptor.
TFD_CLOEXECLinux 2.6.27Set close-on-exec on the new descriptor.
TFD_TIMER_ABSTIMEtimerfd_settime(): treat it_value as an absolute time on the timer's clock.
TFD_TIMER_CANCEL_ON_SETWith ABSTIME on a REALTIME clock: read(2) fails with ECANCELED if the clock jumps.
TFD_IOC_SET_TICKSLinux 3.17ioctl(2) to set the expiration count; for checkpoint/restore.

Errors you will actually hit

errnoMeaning
EINVALclockid is not valid, or flags is invalid.
EPERMAn *_ALARM clock was requested without CAP_WAKE_ALARM.
EMFILEPer-process open file descriptor limit reached.
ENOMEMInsufficient kernel memory to create the timer.
ECANCELEDtimerfd_settime()/read(2): TFD_TIMER_CANCEL_ON_SET timer and the real-time clock changed.

Example

int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (tfd < 0)
    err(1, "timerfd_create");

struct itimerspec its = {
    .it_interval = { .tv_sec = 5 },   /* repeat every 5s */
    .it_value    = { .tv_sec = 5 },   /* first fire in 5s */
};
if (timerfd_settime(tfd, 0, &its, NULL) < 0)
    err(1, "timerfd_settime");

/* when epoll says readable: */
uint64_t expirations;
if (read(tfd, &expirations, sizeof(expirations)) == sizeof(expirations))
    do_periodic_work(expirations);

Trimmed from the full walkthrough in timerfd, signalfd, eventfd: every event source is a file descriptor now.

BSD equivalent

FreeBSD: native timerfd(2) (FreeBSD 14.0), or EVFILT_TIMER in kqueue(2). OpenBSD: EVFILT_TIMER in kqueue(2).

The long version, from the console

Sources

  1. timerfd_create(2), man7.org
  2. timerfd(2), FreeBSD
  3. kqueue(2), FreeBSD
  4. kqueue(2), OpenBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.