timerfd_create(2) System Calls Manual timerfd_create(2) timerfd_create, timerfd_settime, timerfd_gettime - , LIBRARY Standard C library (libc, -lc) #include int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *_Nullable 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_REALTIME . CLOCK_MONOTONIC , , , . CLOCK_BOOTTIME ( Linux 3.15) CLOCK_MONOTONIC, . , CLOCK_MONOTONIC (suspended), CLOCK_BOOTTIME . , . CLOCK_REALTIME , . CLOCK_REALTIME_ALARM ( Linux 3.11) CLOCK_REALTIME, , . CAP_WAKE_ALARM. CLOCK_BOOTTIME_ALARM ( Linux 3.11) CLOCK_BOOTTIME, , . CAP_WAKE_ALARM. See clock_getres(2) for some further details on the above clocks. clock_gettime(2). Linux 2.6.27, timerfd_create() flags ( OR): TFD_NONBLOCK O_NONBLOCK ( open(2)), . fcntl(2) . TFD_CLOEXEC close-on-exec (FD_CLOEXEC) . O_CLOEXEC open(2) , . Linux 2.6.26 flags . timerfd_settime() timerfd_settime() , fd. The new_value argument specifies the initial expiration and interval for the timer. The itimerspec structure used for this argument is described in itimerspec(3type). new_value.it_value , . new_value.it_value . new_value.it_value . new_value.it_interval , , . new_value.it_interval , , , new_value.it_value. , , new_value, (. ., new_value.it_value , clockid). flags. flags , : TFD_TIMER_ABSTIME new_value.it_value . , , new_value.it_value. TFD_TIMER_CANCEL_ON_SET TFD_TIMER_ABSTIME CLOCK_REALTIME CLOCK_REALTIME_ALARM, , (settimeofday(2), clock_settime(2) ). , read(2) ECANCELED. old_value NULL, itimerspec, ; timerfd_gettime() . timerfd_gettime() timerfd_gettime() curr_value, itimerspec, , fd. it_value . , . , , TFD_TIMER_ABSTIME . it_interval . , , , curr_value.it_value. The file descriptor returned by timerfd_create() supports the following additional operations: read(2) If the timer has already expired one or more times since its settings were last modified using timerfd_settime(), or since the last successful read(2), then the buffer given to read(2) returns an unsigned 8-byte integer (uint64_t) containing the number of expirations that have occurred. (The returned value is in host byte order--that is, the native byte order for integers on the host machine.) read(2), , EAGAIN, ( fcntl(2) F_SETFL O_NONBLOCK). read(2) EINVAL, 8 . CLOCK_REALTIME CLOCK_REALTIME_ALARM, (TFD_TIMER_ABSTIME) timerfd_settime() TFD_TIMER_CANCEL_ON_SET, read(2) ECANCELED, ( ). If the associated clock is either CLOCK_REALTIME or CLOCK_REALTIME_ALARM, the timer is absolute (TFD_TIMER_ABSTIME), and the flag TFD_TIMER_CANCEL_ON_SET was not specified when calling timerfd_settime(), then a discontinuous negative change to the clock (e.g., clock_settime(2)) may cause read(2) to unblock, but return a value of 0 (i.e., no bytes read), if the clock change occurs after the time expired, but before the read(2) on the file descriptor. poll(2) select(2) (and similar) ( select(2) readfds; poll(2) POLLIN), . : pselect(2), ppoll(2) epoll(7). ioctl(2) , timerfd: TFD_IOC_SET_TICKS ( Linux 3.17) , . 8- (uint64_t*), . , . -- /. , CONFIG_CHECKPOINT_RESTORE. close(2) , . , , , . fork(2) fork(2) , timerfd_create(). , , read(2) . execve(2) , timerfd_create(), execve(2), , . timerfd_create() . -1, errno . timerfd_settime() timerfd_gettime() 0; -1, errno . timerfd_create() : EINVAL The clockid is not valid. EINVAL flags , Linux 2.6.26 , flags 0. EMFILE . ENFILE . ENODEV () inode. ENOMEM . EPERM clockid was CLOCK_REALTIME_ALARM or CLOCK_BOOTTIME_ALARM but the caller did not have the CAP_WAKE_ALARM capability. timerfd_settime() timerfd_gettime() : EBADF fd . EFAULT new_value, old_value curr_value. EINVAL fd timerfd. timerfd_settime() : ECANCELED . EINVAL new_value ( tv_nsec 0 999999999). EINVAL flags . Linux. Linux 2.6.25, glibc 2.8. Suppose the following scenario for CLOCK_REALTIME or CLOCK_REALTIME_ALARM timer that was created with timerfd_create(): (1) The timer has been started (timerfd_settime()) with the TFD_TIMER_ABSTIME and TFD_TIMER_CANCEL_ON_SET flags; (2) A discontinuous change (e.g., settimeofday(2)) is subsequently made to the CLOCK_REALTIME clock; and (3) the caller once more calls timerfd_settime() to rearm the timer (without first doing a read(2) on the file descriptor). In this case the following occurs: o The timerfd_settime() returns -1 with errno set to ECANCELED. (This enables the caller to know that the previous timer was affected by a discontinuous change to the clock.) o The timer is successfully rearmed with the settings provided in the second timerfd_settime() call. (This was probably an implementation accident, but won't be fixed now, in case there are applications that depend on this behaviour.) timerfd_create() , timer_create(2). . . . . . . : $ 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 #include #include #include #include #include #include static void print_elapsed_time(void) { int secs, nsecs; static int first_call = 1; struct timespec curr; static struct timespec start; if (first_call) { first_call = 0; if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) err(EXIT_FAILURE, "clock_gettime"); } if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) err(EXIT_FAILURE, "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[]) { int fd; ssize_t s; uint64_t exp, tot_exp, max_exp; struct timespec now; struct itimerspec new_value; 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) err(EXIT_FAILURE, "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) err(EXIT_FAILURE, "timerfd_create"); if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1) err(EXIT_FAILURE, "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)) err(EXIT_FAILURE, "read"); tot_exp += exp; print_elapsed_time(); printf("read: %" PRIu64 "; total=%" PRIu64 "\n", exp, 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), timespec(3), epoll(7), time(7) Azamat Hackimov , Dmitry Bolkhovskikh , Yuri Kozlov ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . timerfd_create(2)