名前
timerfd_create, timerfd_settime, timerfd_gettime - ファイルディスクリプター経由で通知するタイマー書式
#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);
説明
これらのシステムコールは、満了通知をファイルディスクリプター経由で配送する タイマーの生成と操作を行う。 これらは、 setitimer(2) や timer_create(2) を用いる方法の代わりとなるものであり、このファイルディスクリプターを select(2), poll(2), epoll(7) で監視できるという利点がある。timerfd_create()
timerfd_create() は新規のタイマーオブジェクトを生成し、そのタイマーを参照するファイル ディスクリプターを返す。 clockid 引き数は、タイマーの進捗を管理するためのクロックを指定するもので、 CLOCK_REALTIME か CLOCK_MONOTONIC のいずれかでなければならない。 CLOCK_REALTIME はシステム全体で使用されるクロックで、このクロックは変更可能である。 CLOCK_MONOTONIC は変更されることのないクロックで、(システム時刻の手動での変更などの) システムクロックの不連続な変化の影響を受けない。 これらのクロックの現在の値は clock_gettime(2) を使って取得できる。- TFD_NONBLOCK
- 新しく生成されるオープンファイル記述 (open file description) の O_NONBLOCK ファイルステータスフラグをセットする。 このフラグを使うことで、 O_NONBLOCK をセットするために fcntl(2) を追加で呼び出す必要がなくなる。
- TFD_CLOEXEC
- 新しいファイルディスクリプターに対して close-on-exec ( FD_CLOEXEC) フラグをセットする。 このフラグが役に立つ理由については、 open(2) の O_CLOEXEC フラグの説明を参照のこと。
timerfd_settime()
timerfd_settime() は、ファイルディスクリプター fd により参照されるタイマーを開始したり停止したりする。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 を設定すると、タイマーが停止する。
timerfd_gettime()
timerfd_gettime() は、ファイルディスクリプター fd で参照されるタイマーの現在の設定が入った itimerspec 構造体を、 curr_value に格納して返す。タイマーファイルディスクリプターに対する操作
timerfd_create() が返すファイルディスクリプターは以下の操作をサポートしている。- read(2)
- timerfd_settime() を使ってタイマーの設定が最後変更されて以降、または read(2) の呼び出しに最後に成功して以降に、タイマーの満了が一回以上発生していれば、 read(2) に渡されたバッファーに、タイマー満了回数を示す 8 バイトの unsigned 型の整数 ( uint64_t) が返される (返される値はホストバイトオーダ、つまりそのホストマシンにおける 整数の通常のバイトオーダである)。
- read(2) を行った時点でタイマーの満了が発生していなければ、 read(2) は停止 (block) する、もしくはファイルディスクリプターが 非停止 (nonblocking) に設定されている場合はエラー EAGAIN で失敗する (非停止モードにするには、 fcntl(2) の F_SETFL 命令で O_NONBLOCK フラグをセットする)。
- 渡されたバッファーの大きさが 8 バイト未満の場合、 read(2) はエラー EINVAL で失敗する。
- poll(2), select(2) (と同様の操作)
- 一つ以上のタイマー満了が発生していれば、 ファイルディスクリプターは読み出し可能となる ( select(2) の readfds 引き数や poll(2) の POLLIN フラグ)。
- このファイルディスクリプターは、他のファイルディスクリプター多重 API である pselect(2), ppoll(2), epoll(7) もサポートしている。
- close(2)
- ファイルディスクリプターがそれ以降は必要なくなった際には、クローズすべきである。 同じ timer オブジェクトに関連付けられたファイルディスクリプターが全て クローズされると、そのタイマーは解除され、 そのオブジェクト用の資源がカーネルにより解放される。
fork(2)_での扱い">fork(2)_%E3%81%A7%E3%81%AE%E6%89%B1%E3%81%84">fork(2) での扱い
fork(2) が行われると、子プロセスは timerfd_create() により生成されたファイルディスクリプターのコピーを 継承する。そのファイルディスクリプターは、親プロセスの対応する ファイルディスクリプターと同じタイマーオブジェクトを参照しており、 子プロセスの read(2) でも同じタイマーの満了に関する情報が返される。execve(2)_での扱い">execve(2)_%E3%81%A7%E3%81%AE%E6%89%B1%E3%81%84">execve(2) での扱い
execve(2) の前後で timerfd_create() により生成されたファイルディスクリプターは保持され、 タイマーが開始されていた場合にはタイマーの満了が発生し続ける。返り値
成功すると、 timerfd_create() は新しいファイルディスクリプターを返す。 エラーの場合、-1 を返し、 errno にエラーを示す値を設定する。エラー
timerfd_create() は以下のエラーで失敗する可能性がある。- EINVAL
- clockid 引き数が CLOCK_MONOTONIC でも CLOCK_REALTIME でもない。
- EINVAL
- flags が無効である。もしくは、Linux 2.6.26 以前の場合には flags が 0 以外である。
- EMFILE
- オープン済みのファイルディスクリプターの数がプロセスあたりの上限に 達していた。
- ENFILE
- オープン済みのファイル総数がシステム全体の上限に達していた。
- ENODEV
- (カーネル内の) 無名 inode デバイスをマウントできなかった。
- ENOMEM
- タイマーを作成するのに十分なカーネルメモリーがなかった。
- EBADF
- fd が有効なファイルディスクリプターでない。
- EFAULT
- new_value, old_value, curr_value が有効なポインターではない。
- EINVAL
- fd が有効な timerfd ファイルディスクリプターでない。
- EINVAL
- new_value が適切に初期化されていない ( tv_nsec の一つが 0 から 999,999,999 までの範囲に入っていない)。
- EINVAL
- flags が無効である。
バージョン
これらのシステムコールはカーネル 2.6.25 以降の Linux で利用可能である。 ライブラリ側のサポートはバージョン 2.8 以降の glibc で提供されている。準拠
これらのシステムコールは Linux 固有である。バグ
現在のところ、 timerfd_create() が対応している clockid の種類は timer_create(2) よりも少ない。例
以下のプログラムは、タイマーを作成し、その進捗をモニターするものである。 このプログラムは最大で 3 個のコマンドライン引き数を取り、 第一引き数ではタイマーの満了時間の初期値 (秒数単位) を、 第二引き数ではタイマーの間隔 (秒数単位) を、 第三引き数ではタイマーが何回満了したらプログラムが終了するかを指定する。 第二引き数と第三引き数は省略可能である。$ 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); }
関連項目
eventfd(2), poll(2), read(2), select(2), setitimer(2), signalfd(2), timer_create(2), timer_gettime(2), timer_settime(2), epoll(7), time(7)この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部である。 プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。2011-09-14 | Linux |