What kind of timer?

Having created the timer, you now have to decide what kind of timer it is. This is done by a combination of arguments to timer_settime(), the function used to actually start the timer:

#include <time.h>

int
timer_settime (timer_t timerid,
               int flags,
               struct itimerspec *value,
               struct itimerspec *oldvalue);

The timerid argument is the value that you got back from the timer_create() function call—you can create a bunch of timers, and then call timer_settime() on them individually to set and start them at your convenience.

The flags argument is where you specify absolute versus relative.

If you pass the constant TIMER_ABSTIME, then it's absolute, pretty much as you'd expect. You then pass the actual date and time when you want the timer to go off.

If you pass a zero, then the timer is considered relative to the current time.

Let's look at how you specify the times. Here are key portions of two data structures (in <time.h>):

struct timespec {
    long    tv_sec,
            tv_nsec;
};

struct itimerspec {
    struct timespec it_value,
                    it_interval;
};

There are two members in struct itimerspec:

it_value
the one-shot value
it_interval
the reload value

The it_value specifies either how long from now the timer should go off (in the case of a relative timer), or when the timer should go off (in the case of an absolute timer). Once the timer fires, the it_interval value specifies a relative value to reload the timer with so that it can trigger again. Note that specifying a value of zero for the it_interval makes it into a one-shot timer. You might expect that to create a “pure” periodic timer, you'd just set the it_interval to the reload value, and set it_value to zero. Unfortunately, the last part of that statement is false—setting the it_value to zero disables the timer. If you want to create a pure periodic timer, set it_value equal to it_interval and create the timer as a relative timer. This will fire once (for the it_value delay) and then keep reloading with the it_interval delay.

Both the it_value and it_interval members are actually structures of type struct timespec, another POSIX thing. The structure lets you specify sub-second resolutions. The first member, tv_sec, is the number of seconds; the second member, tv_nsec, is the number of nanoseconds in the current second. (What this means is that you should never set tv_nsec past the value 1 billion—this would imply more than a one-second offset.)

Here are some examples:

it_value.tv_sec = 5;
it_value.tv_nsec = 500000000;
it_interval.tv_sec = 0;
it_interval.tv_nsec = 0;

This creates a one-shot timer that goes off in 5.5 seconds. (We got the “.5” because of the 500,000,000 nanoseconds value.)

We're assuming that this is used as a relative timer, because if it weren't, then that time would have elapsed long ago (5.5 seconds past January 1, 1970, 00:00 GMT).

Here's another example:

it_value.tv_sec = 987654321;
it_value.tv_nsec = 0;
it_interval.tv_sec = 0;
it_interval.tv_nsec = 0;

This creates a one-shot timer that goes off Thursday, April 19, 2001 at 00:25:21 EDT. (There are a bunch of functions that help you convert between the human-readable date and the “number of seconds since January 1, 1970, 00:00:00 GMT” representation. Take a look in the C library at time(), asctime(), ctime(), mktime(), strftime(), etc.)

For this example, we're assuming that it's an absolute timer, because of the huge number of seconds that we'd be waiting if it were relative (987654321 seconds is about 31.3 years).

Note that in both examples, I've said, “We're assuming that…” There's nothing in the code for timer_settime() that checks those assumptions and does the “right” thing! You have to specify whether the timer is absolute or relative yourself. The kernel will happily schedule something 31.3 years into the future.

One last example:

it_value.tv_sec = 1;
it_value.tv_nsec = 0;
it_interval.tv_sec = 0;
it_interval.tv_nsec = 500000000;

Assuming it's relative, this timer will go off in one second, and then again every half second after that. There's absolutely no requirement that the reload values look anything like the one-shot values.