Skip to content

Archive

Timers

8 articles
Linux 23 Sep 2026 4 min read

TFD_TIMER_CANCEL_ON_SET Turns Realtime Clock Jumps into ECANCELED

An absolute timer tied to CLOCK_REALTIME has a dependency that a monotonic deadline does not: an administrator, synchronization service, or privileged process can move the wall clock discontinuously while the timer is armed. Linux timerfd can expose that event explicitly. With TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, a qualifying clock jump causes a current or later read() on the timer descriptor to fail with ECANCELED. This behavior separates two events that would otherwise be easy to conflate: reaching a scheduled wall-clock instant and invalidating the clock basis used to schedule it.

Linux 19 Sep 2026 5 min read

timerfd Reads Count Periodic Expirations

A periodic timer can expire several times before a busy event loop gets CPU time again. Linux timerfd does not compress that delay into a bare “timer fired” notification. A successful read() returns an unsigned 64-bit count of expirations accumulated since the timer was armed or since the preceding successful read. That counter changes the semantics of delayed timer handling. Readiness says at least one expiration is pending; the value read from the descriptor says how many periods elapsed.

Software Engineering 18 Sep 2026 5 min read

timerfd Turns Timer Expirations into Descriptor Readiness

A timerfd becomes readable after its timer expires. The notification is not a signal handler invocation and not a byte-stream message. Linux records pending expirations on a timer object and exposes that state through a file descriptor, so a timer can occupy the same readiness boundary as sockets, pipes, and other descriptors. That interface does more than replace one notification mechanism with another. Clock selection determines the time domain, arming flags determine whether a deadline is relative or absolute, and each successful read reports the number of expirations accumulated since the preceding successful read or timer reconfiguration.

Software Engineering 17 Sep 2026 4 min read

timerfd Counts Expirations Through Descriptor Reads

A periodic timerfd can expire several times before user space reads it. The next successful read() does not report only the most recent tick: it returns an unsigned 64-bit count of expirations accumulated since the previous successful read, or since the timer was configured if no read has completed yet. That behavior makes a timer an event-loop object without converting each expiration into a signal. The descriptor becomes readable when at least one expiration is pending, and the same descriptor can participate in poll(), select(), or epoll() beside sockets, pipes, and other descriptor-backed event sources.

Software Engineering 17 Sep 2026 4 min read

Linux timerfd Read Reports Accumulated Expirations

A periodic Linux timerfd can expire several times before an event loop reads it. The next successful read() does not return one record per wakeup. It returns one host-order uint64_t containing the number of expirations accumulated since the timer was last armed or since the preceding successful read. That count makes timerfd readiness a notification that timer state is consumable, not a one-to-one mapping between scheduler wakeups and timer periods.

Software Engineering 17 Sep 2026 6 min read

Linux timerfd Makes Missed Periods Observable as Expiration Counts

A periodic Linux timerfd can expire several times before an event loop runs again. The next successful read() does not merely report that the timer fired; it returns an unsigned 64-bit count of expirations accumulated since the previous successful read or since the timer was last configured. Delayed dispatch therefore becomes observable as a count rather than a sequence of queued timer records. That contract separates timer schedule from consumer execution. A process may be descheduled, an event loop may spend time on other descriptors, or several periods may pass before the timerfd is consumed. The kernel tracks expirations, while application code decides what multiple expirations mean for the work associated with them.

Go 08 Sep 2026 9 min read

Use Go Timers Correctly After Go 1.23

Timer code in Go has accumulated a surprising amount of folklore. Older examples warn that time.After leaks resources, insist that every stopped timer channel must be drained, and wrap Timer.Reset in careful stop-and-drain sequences. Those rules were important for older Go programs. They are not all current rules. Go 1.23 changed the implementation and guarantees of channel-based timers. Unreferenced timers can now be garbage collected before they fire, and timer channels use synchronous semantics that prevent stale values after Stop or Reset returns. The result is simpler timer code—but only when the program is actually using the new semantics.

Linux 04 Sep 2026 11 min read

Integrate Timers into Linux Event Loops with timerfd

Event loops work best when unrelated kinds of work have one common waiting mechanism. Sockets become readable. Pipes become writable. A child-process descriptor or signal descriptor can become ready. Timers are often the awkward exception. A program can call sleep() or nanosleep(), but that blocks the thread instead of letting it wait for I/O. It can pass a timeout to poll() or epoll_wait(), but one timeout becomes difficult to manage when the program has several independent deadlines. Traditional POSIX timers can deliver signals, which introduces a second asynchronous control path.