#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
これらのシステムコールを使うのは、それぞれ timer_create(2), timer_settime(2), timer_gettime(2) を使うのと同様である (timer_getoverrun(2) に対応するものはなく、以下で説明するように この機能は read(2) により提供される)。
Linux 2.6.27 以降では、 以下の値のいくつかをビット単位の論理和 (OR) で指定することで、 timerfd_create() の振舞いを変更することができる。
バージョン 2.6.26 以前の Linux では、 flags 引き数は未使用であり、0 を指定しなければならない。
new_value 引き数は、タイマーの満了時間 (expiration) の初期値と間隔 (interval) を 指定する。この引き数で使用されている itimerspec 構造体には 2 つのフィールドがあり、各フィールドは timespec 型の構造体である。
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer */
struct timespec it_value; /* Initial expiration */
};
new_value.it_value はタイマーの満了時間の初期値を、秒とナノ秒で指定する。 new_value.it_value のフィールドのうち少なくとも一方に 0 以外の値を設定すると、 タイマーが開始される。 両方のフィールドに 0 を設定すると、タイマーが停止する。
new_value.it_interval はタイマーの一回目の満了後に繰り返しタイマーの満了間隔を、秒とナノ秒で指定する。 new_value.it_interval のフィールドのうち少なくとも一方に 0 以外の値を設定すると、 繰り返しタイマーが有効になる。 両方のフィールドに 0 を設定した場合、タイマーは new_value.it_value で指定された時間後に、一回だけ満了して停止する。
flags 引き数には 0 か TFD_TIMER_ABSTIME を指定する。 0 は相対時刻タイマーを意味し、 new_value.it_value では clockid で指定されたクロックの現在の値からの相対的な時刻を指定する。 TFD_TIMER_ABSTIME は絶対時刻タイマーを意味し、 new_value.it_interval では clockid で指定されたクロックの絶対時刻を指定する。 つまり、クロックの値が new_value.it_interval で指定された時刻に達したら、タイマーが満了する。
old_value 引き数が NULL でない場合、 old_value 引き数が指す itimerspec 構造体は、 timerfd_settime() を呼び出した時点でのタイマーの設定を返すのに使用される。 下記の timerfd_gettime() の説明を参照。
it_value フィールドは、タイマーが次に満了するまでの残り時間を返す。 この構造体の両方のフィールドが 0 であれば、タイマーは現在停止している。 タイマー設定時に TFD_TIMER_ABSTIME フラグが指定されたかに関わらず、このフィールドは常に相対値が格納される。
it_interval フィールドは、タイマーの間隔を返す。 この構造体の両方のフィールドが 0 であれば、タイマーは new_value.it_value で指定された時間後に一回だけ満了して停止するように設定されている。
timerfd_settime() と timerfd_gettime() は成功すると 0 を返す。 エラーの場合、-1 を返し、 errno にエラーを示す値を設定する。
timerfd_settime() と timerfd_gettime() は以下のエラーで失敗する可能性がある。
timerfd_settime() は以下のエラーで失敗することもある。
以下のシェルのセッションはこのプログラムの使用例を示したものである。
$ a.out 3 1 100 0.000: timer started 3.000: read: 1; total=1 4.000: read: 1; total=2 ^Z # type control-Z to suspend the program [1]+ Stopped ./timerfd3_demo 3 1 100 $ fg # Resume execution after a few seconds a.out 3 1 100 9.660: read: 5; total=7 10.000: read: 1; total=8 11.000: read: 1; total=9 ^C # type control-C to suspend the program
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> /* Definition of uint64_t */
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void
print_elapsed_time(void)
{
static struct timespec start;
struct timespec curr;
static int first_call = 1;
int secs, nsecs;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
handle_error("clock_gettime");
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
handle_error("clock_gettime");
secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int
main(int argc, char *argv[])
{
struct itimerspec new_value;
int max_exp, fd;
struct timespec now;
uint64_t exp, tot_exp;
ssize_t s;
if ((argc != 2) && (argc != 4)) {
fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
handle_error("clock_gettime");
/* Create a CLOCK_REALTIME absolute timer with initial
expiration and interval as specified in command line */
new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
new_value.it_value.tv_nsec = now.tv_nsec;
if (argc == 2) {
new_value.it_interval.tv_sec = 0;
max_exp = 1;
} else {
new_value.it_interval.tv_sec = atoi(argv[2]);
max_exp = atoi(argv[3]);
}
new_value.it_interval.tv_nsec = 0;
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
handle_error("timerfd_create");
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
handle_error("timerfd_settime");
print_elapsed_time();
printf("timer started\n");
for (tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read");
tot_exp += exp;
print_elapsed_time();
printf("read: %llu; total=%llu\n",
(unsigned long long) exp,
(unsigned long long) tot_exp);
}
exit(EXIT_SUCCESS);
}