read
is called on them.
Thus, one can be substituted for the other without an application knowing,
assuming it only calls read
.
For both,
you read exactly one 64-bit integer at a time, and if that integer would be 0, read
blocks.
With timerfd, this is the number of timer expirations since the last read
;
with eventfd, this is the number of events that have been written to the eventfd since the last read
.
So, timerfd can be emulated by simply writing to an eventfd from a userspace process every N seconds.
Indeed, we can think of "timerfds" as a specialized kind of eventfd, specially optimized by the kernel, for the common case of triggering an event on a timer.
This opens up some interesting possibilities.
First, let's imagine that we live in a world where programs are habitually written in a object-capability style using file descriptors. Like with Capsicum or CloudABI or UCSPI.
In this world, we could use timerfds rather than strings to configure things relating to time.
For example, rather than passing cron the text string 0 * * * *
to run a job every hour,
we could instead pass a timerfd which is configured to expire every hour.
Then cron would run select on that timerfd, among others,
and when a timerfd expires,
cron would run the relevant job.
One can imagine similar schemes for many other forms of time handling which currently are done with inert data.
Indeed, we could universally use timerfd for all interactions with time;
a well-designed program would never use clock_gettime
,
but instead would only ever wait for various timerfds to expire.
Then, for programs that are designed to use timerfds in this way, eventfd provides a way to put "time" under userspace control, without use of privileges or namespaces.
A cron designed to use timerfds would not be just a way to run jobs at specific times. Rather, it would be a fully generic tool for running a job on any event, so long as it's notified of that event through an eventfd-compatible file descriptor, which can be passed in to cron from any arbitrary external source.
Likewise for other programs; rather than being bound to just working with time, they can also work with any other kind of events.
Since time-based events are generally just approximations for the hard-to-work-with actual events, this is a generally useful change. Programs which today wait for an event by looping over a flag-check and a (timerfd-based) sleep, can later wait directly for the event through an eventfd.
This would also be useful to ensure deterministic tests for applications which rely on time.
This increase in expressiveness is just a consequence of the power of both the object-capability paradigm and Linux. Using file descriptors as capabilities perfectly harmonizes this paradigm with Linux, and allows for mechanisms like the one described here.