Skip to content(if available)orjump to list(if available)

The missing cross-platform OS API for timers

pjc50

Very minor point: Windows applications only come with a message queue if you explicitly start one, so if you have a headless application it needs to have an invisible "window". However I agree with the author that it is a pretty nice API in general. There are some problems caused by the very limited parameter size, but it's a standard notification API for asynchronous OS events. We use it headlessly for detecting USB insertions.

hkwerf

This article fails to separate the concerns one has with timers. There's three cases I see:

The simple case is just putting a thread to sleep for a given time. It's somewhat odd that there's no portable API for that, granted. At least POSIX has sleep, nanosleep and clock_nanosleep (list edited, thanks oguz-ismail).

The second case is that a thread wants to continue processing until a timer has passed. This has to happen cooperatively one way or another, so setting a timer is equivalent to regularly querying the system time and comparing to a limit. There is simply no need for a "timer" operating system facility. (Even if you were to plug POSIX timers in here, you'd in all likelihood still need to check some flag set in the signal handler in the processing thread. And then you'd still need to check the system time as signals can originate from anywhere, just as with sleep/etc. above.)

In the third case, a thread waits for I/O. Then, of course, the call to that I/O facility defines how any timer is handled. As these facilities are not portable, timers aren't portable. The author refers to this realization as the need to implement "Userspace timers". These are just an artifact of the I/O facility and calls querying the system time, though.

So, ultimately, not having portable timers is the least of our problems. So long as we don't unify select, poll, kqueue, io_uring and what not, we don't have a need for them. And, as the author realized, libraries like libuv, which do an acceptable job at unifying those facilities, tend to provide a portable timer API.

amelius

Another consideration: often you want to wait for several types of object (timer, semaphore, file, etc.), so you need one interface where you can do wait([A, B, C, ...]) where A can be a timer and B a semaphore, C a file, etc. Basically, the OS should present a unified interface.

oguz-ismail

>usleep

Not since 2008. POSIX has sleep(), nanosleep() and clock_nanosleep() now

hkwerf

Thanks, I've edited the list. :)

Someone

> so setting a timer is equivalent to regularly querying the system time and comparing to a limit

Setting an OS timer would make the thread use 0% CPU. “Regularly querying the system time and comparing to a limit” would not.

Also, a good OS API would allow callers to specify how important it is to be woken at that exact moment, and would use that information to coordinate wake-up times across processes, and thus maximize idle periods.

hkwerf

> Setting an OS timer would make the thread use 0% CPU. “Regularly querying the system time and comparing to a limit” would not.

As mentioned, this is the first case and can be achieved by calls to sleep/Sleep/etc. You'd only regularly query if there is actual useful work to be done. That's the premise of the second case you quoted from.