focal (2) timerfd_create.2.gz

Provided by: manpages-ja-dev_0.5.0.0.20180315+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/ に書かれている。