Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all bug

名前

       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)   で監視できるという利
       点がある。

       これらのシステムコールを使うのは、それぞれ        timer_create(2),       timer_settime(2),
       timer_gettime(2)  を使うのと同様である (timer_getoverrun(2) に対応するものはなく、以下で説
       明するように この機能は read(2)  により提供される)。

   timerfd_create()
       timerfd_create()      は新規のタイマーオブジェクトを生成し、そのタイマーを参照するファイル
       ディスクリプターを返す。 clockid  引き数は、タイマーの進捗を管理するためのクロックを指定す
       るもので、 CLOCK_REALTIMECLOCK_MONOTONIC のいずれかでなければならない。 CLOCK_REALTIME
       はシステム全体で使用されるクロックで、このクロックは変更可能である。 CLOCK_MONOTONIC  は変
       更されることのないクロックで、(システム時刻の手動での変更などの)  システムクロックの不連続
       な変化の影響を受けない。 これらのクロックの現在の値は  clock_gettime(2)   を使って取得でき
       る。

       Linux  2.6.27  以降では、  以下の値のいくつかをビット単位の論理和  (OR) で指定することで、
       timerfd_create() の振舞いを変更することができる。

       TFD_NONBLOCK  新しく生成されるオープンファイル記述 (open file description)  の  O_NONBLOCK
                     ファイルステータスフラグをセットする。  このフラグを使うことで、  O_NONBLOCK
                     をセットするために fcntl(2) を追加で呼び出す必要がなくなる。

       TFD_CLOEXEC   新しいファイルディスクリプターに対して close-on-exec (FD_CLOEXEC)   フラグを
                     セットする。 このフラグが役に立つ理由については、 open(2)  の O_CLOEXEC フラ
                     グの説明を参照のこと。

       バージョン 2.6.26 以前の Linux では、 flags 引き数は未使用であり、0 を指定しなければならな
       い。

   timerfd_settime()
       timerfd_settime()   は、ファイルディスクリプター fd により参照されるタイマーを開始したり停
       止したりする。

       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() の説明を参照。

   timerfd_gettime()
       timerfd_gettime()   は、ファイルディスクリプター fd で参照されるタイマーの現在の設定が入っ
       た itimerspec 構造体を、 curr_value に格納して返す。

       it_value   フィールドは、タイマーが次に満了するまでの残り時間を返す。   この構造体の両方の
       フィールドが  0  であれば、タイマーは現在停止している。 タイマー設定時に TFD_TIMER_ABSTIME
       フラグが指定されたかに関わらず、このフィールドは常に相対値が格納される。

       it_interval フィールドは、タイマーの間隔を返す。 この構造体の両方のフィールドが  0  であれ
       ば、タイマーは new_value.it_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)  が行われると、子プロセスは timerfd_create()  により生成されたファイルディスクリプ
       ターのコピーを 継承する。そのファイルディスクリプターは、親プロセスの対応する ファイルディ
       スクリプターと同じタイマーオブジェクトを参照しており、 子プロセスの read(2)   でも同じタイ
       マーの満了に関する情報が返される。

   execve(2) での扱い
       execve(2)  の前後で timerfd_create()  により生成されたファイルディスクリプターは保持され、
       タイマーが開始されていた場合にはタイマーの満了が発生し続ける。

返り値

       成功すると、 timerfd_create()   は新しいファイルディスクリプターを返す。  エラーの場合、-1
       を返し、 errno にエラーを示す値を設定する。

       timerfd_settime()  と timerfd_gettime()  は成功すると 0 を返す。 エラーの場合、-1 を返し、
       errno にエラーを示す値を設定する。

エラー

       timerfd_create()  は以下のエラーで失敗する可能性がある。

       EINVAL clockid 引き数が CLOCK_MONOTONIC でも CLOCK_REALTIME でもない。

       EINVAL flags が無効である。もしくは、Linux 2.6.26 以前の場合には flags が 0 以外である。

       EMFILE オープン済みのファイルディスクリプターの数がプロセスあたりの上限に 達していた。

       ENFILE オープン済みのファイル総数がシステム全体の上限に達していた。

       ENODEV (カーネル内の) 無名 inode デバイスをマウントできなかった。

       ENOMEM タイマーを作成するのに十分なカーネルメモリーがなかった。

       timerfd_settime()  と timerfd_gettime()  は以下のエラーで失敗する可能性がある。

       EBADF  fd が有効なファイルディスクリプターでない。

       EFAULT new_value, old_value, curr_value が有効なポインターではない。

       EINVAL fd が有効な timerfd ファイルディスクリプターでない。

       timerfd_settime()  は以下のエラーで失敗することもある。

       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/ に書かれている。