Inspired by the last leap second, I've been exploring timing (specifically, interval timers) using POSIX calls.
POSIX provides several ways to set up timers, but they're all problematic:
sleep
andnanosleep
—these are annoying to restart after they're interrupted by a signal, and they introduce clock skew. You can avoid some, but not all, of this skew with some extra work, but these functions use the realtime clock, so this isn't without pitfalls.setitimer
or the more moderntimer_settime
—these are designed to be interval timers, but they're per-process, which is a problem if you need multiple active timers. They also can't be used synchronously, but that's less of a big deal.clock_gettime
andclock_nanosleep
seem like the right answer when used withCLOCK_MONOTONIC
.clock_nanosleep
supports absolute timeouts, so you can just sleep, increment the timeout, and repeat. It's easy to restart after an interruption that way, too. Unfortunately, these functions might as well be Linux-specific: there's no support for them on Mac OS X or FreeBSD.pthread_cond_timedwait
is available on the Mac and can work withgettimeofday
as a kludgy workaround, but on the Mac it can only work with the realtime clock, so it's subject to misbehavior when the system clock is set or a leap second happens.
Is there an API I'm missing? Is there a reasonably portable way to create well-behaved interval timers on UNIX-like systems, or does this sum up the state of things today?
By well-behaved and reasonably portable, I mean:
- Not prone to clock skew (minus, of course, the system clock's own skew)
- Resilient to the system clock being set or a leap second occurring
- Able to support multiple timers in the same process
- Available on at least Linux, Mac OS X, and FreeBSD
A note on leap seconds (in response to R..'s answer):
POSIX days are exactly 86,400 seconds long, but real-world days can rarely be longer or shorter. How the system resolves this discrepancy is implementation-defined, but it's common for the leap second to share the same UNIX timestamp as the previous second. See also: Leap Seconds and What To Do With Them.
The Linux kernel leap second bug was a result of failing to do housekeeping after setting the clock back a second: https://lkml.org/lkml/2012/7/1/203. Even without that bug, the clock would have jumped backwards one second.