diff options
Diffstat (limited to 'man2/timerfd_create.2')
| -rw-r--r-- | man2/timerfd_create.2 | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/man2/timerfd_create.2 b/man2/timerfd_create.2 new file mode 100644 index 0000000000..8245c0914d --- /dev/null +++ b/man2/timerfd_create.2 @@ -0,0 +1,508 @@ +.\" Copyright (C) 2008 Michael Kerrisk <mtk.manpages@gmail.com> +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, +.\" MA 02111-1307 USA +.\" +.TH TIMERFD_CREATE 2 2008-02-19 Linux "Linux Programmer's Manual" +.SH NAME +timerfd_create, timerfd_settime, timerfd_gettime \- +timers that notify via file descriptors +.SH SYNOPSIS +.\" FIXME verify that this is the right header file in glibc +.nf +.B #include <sys/timerfd.h> +.sp +.BI "int timerfd_create(int " clockid ", int " flags ); +.sp +.BI "int timerfd_settime(int " fd ", int " flags , +.BI " const struct itimerspec *" new_value , +.BI " struct itimerspec *" curr_value ); +.sp +.BI "int timerfd_gettime(int " fd ", struct itimerspec *" curr_value ); +.fi +.SH DESCRIPTION +These system calls create and operate on a timer +that delivers timer expiration notifications via a file descriptor. +They provide an alternative to the use of +.BR setitimer (2) +or +.BR timer_create (3), +with the advantage that the file descriptor may be monitored by +.BR select (2), +.BR poll (2), +and +.BR epoll (7). + +The use of these three system calls is analogous to the use of +.BR timer_create (3), +.BR timer_settime (3), +and +.BR timer_gettime (3). +(There is no analog of +.BR timer_gettoverrun (3), +since that functionality is provided by +.BR read (2), +as described below.) +.\" +.SS timerfd_create() +.BR timerfd_create () +creates a new timer object, +and returns a file descriptor that refers to that timer. +The +.I clockid +argument specifies the clock that is used to mark the progress +of the timer, and must be either +.B CLOCK_REALTIME +or +.BR CLOCK_MONOTONIC . +.B CLOCK_REALTIME +is a settable system-wide clock. +.B CLOCK_MONOTONIC +is a non-settable clock that is not affected +by discontinuous changes in the system clock +(e.g., manual changes to system time). +The current value of each of these clocks can be retrieved using +.BR clock_gettime (3). + +The +.I flags +argument is reserved for future use. +.\" Eventually it will probably allow O_CLOEXEC and maybe O_NONBLOCK. +As at Linux 2.6.25, this argument must be specified as zero. +.\" +.SS timerfd_settime() +.BR timerfd_settime () +arms (starts) or disarms (stops) +the timer referred to by the file descriptor +.IR fd . + +The +.I new_value +argument specifies the initial expiration and interval for the timer. +The +.I itimer +structure used for this argument contains two fields, +each of which is in turn a structure of type +.IR timespec : +.in +4n +.nf + +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 */ +}; +.fi +.in +.PP +.I new_value.it_value +specifies the initial expiration of the timer, +in seconds and nanoseconds. +Setting either field of +.I new_value.it_value +to a nonzero value arms the timer. +Setting both fields of +.I new_value.it_value +to zero disarms the timer. + +Setting one or both fields of +.I new_value.it_interval +to nonzero values specifies the period, in seconds and nanoseconds, +for repeated timer expirations after the initial expiration. +If both fields of +.I new_value.it_interval +are zero, the timer expires just once, at the time specified by +.IR new_value.it_value . + +The +.I flags +argument is either 0, to start a relative timer +.RI ( new_value.it_interval +specifies a time relative to the current value of the clock specified by +.IR clockid ), +or +.BR TFD_TIMER_ABSTIME , +to start an absolute timer +.RI ( new_value.it_interval +specifies an absolute time for the clock specified by +.IR clockid ; +that is, the timer will expire when the value of that +clock reaches the value specified in +.IR new_value.it_interval ). + +The +.I curr_value +argument returns a structure containing the setting of the timer that +was current at the time of the call; see the description of +.BR timerfd_gettime () +following. +.\" +.SS timerfd_gettime() +.BR timerfd_gettime () +returns, in +.IR curr_value , +an +.IR itimerspec +that contains the current setting of the timer +referred to by the file descriptor +.IR fd . + +The +.I it_value +field returns the amount of time +until the timer will next expire. +If both fields of this structure are zero, +then the timer is currently disarmed. +This field always contains a relative value, regardless of whether the +.BR TFD_TIMER_ABSTIME +flag was specified when setting the timer. + +The +.I it_interval +field returns the interval of the timer. +If both fields of this structure are zero, +then the timer is set to expire just once, at the time specified by +.IR curr_value.it_value . +.SS Operating on a timer file descriptor +The file descriptor returned by +.BR timerfd_create () +supports the following operations: +.TP +.BR read (2) +If the timer has already expired one or more times since +its settings were last modified using +.BR timerfd_settime (), +or since the last successful +.BR read (2), +then the buffer given to +.BR read (2) +returns an unsigned 8-byte integer +.RI ( uint64_t ) +containing the number of expirations that have occurred. +(The returned value is in host byte order, +i.e., the native byte order for integers on the host machine.) +.IP +If no timer expirations have occurred at the time of the +.BR read (2), +then the call either blocks until the next timer expiration, +or fails with the error +.B EAGAIN +if the file descriptor has been made non-blocking +(via the use of the +.BR fcntl (2) +.B F_SETFL +operation to set the +.B O_NONBLOCK +flag). +.IP +A +.BR read (2) +will fail with the error +.B EINVAL +if the size of the supplied buffer is less than 8 bytes. +.TP +.BR poll "(2), " select "(2) (and similar)" +The file descriptor is readable +(the +.BR select (2) +.I readfds +argument; the +.BR poll (2) +.B POLLIN +flag) +if one or more timer expirations have occurred. +.IP +The file descriptor also supports the other file-descriptor +multiplexing APIs: +.BR pselect (2), +.BR ppoll (2), +and +.BR epoll (7). +.TP +.BR close (2) +When the file descriptor is no longer required it should be closed. +When all file descriptors associated with the same timer object +have been closed, +the timer is disarmed and its resources are freed by the kernel. +.\" +.SS fork(2) semantics +After a +.BR fork (2), +the child inherits a copy of the file descriptor created by +.BR timerfd_create (). +The file descriptor refers to the same underlying +timer object as the corresponding file descriptor in the parent, +and +.BR read (2)s +in the child will return information about +expirations of the timer. +.\" +.SS execve(2) semantics +A file descriptor created by +.BR timerfd_create () +is preserved across +.BR execve (2), +and continues to generate timer expirations if the timer was armed. +.SH "RETURN VALUE" +On success, +.BR timerfd_create () +returns a new file descriptor. +On error, \-1 is returned and +.I errno +is set to indicate the error. + +.BR timerfd_settime () +and +.BR timerfd_gettime () +return 0 on success; +on error they return \-1, and set +.I errno +to indicate the error. +.SH ERRORS +.BR timerfd_create () +can fail with the following errors: +.TP +.B EINVAL +The +.I clockid +argument is neither +.B CLOCK_MONOTONIC +nor +.BR CLOCK_REALTIME ; +or +.I flags +is invalid. +.TP +.B EMFILE +The per-process limit of open file descriptors has been reached. +.TP +.B ENFILE +The system-wide limit on the total number of open files has been +reached. +.TP +.B ENODEV +Could not mount (internal) anonymous inode device. +.TP +.B ENOMEM +There was insufficient kernel memory to create the timer. +.PP +.BR timerfd_settime () +and +.BR timerfd_gettime () +can fail with the following errors: +.TP +.B EBADF +.I fd +is not a valid file descriptor. +.TP +.B EINVAL +.I fd +is not a valid timerfd file descriptor. +.I new_value +is not properly initialized (one of the +.I tv_nsec +falls outside the range zero to 999,999,999). +.SH VERSIONS +These system calls are available on Linux since kernel 2.6.25. +.\" FIXME . check later to see when glibc support is provided +As at February 2008 (glibc 2.7), the details of the glibc interface +have not been finalized, so that, for example, +the eventual header file may be different from that shown on this page. +.SH CONFORMING TO +These system calls are Linux-specific. +.SH EXAMPLE +The following program creates a timer and then monitors its progress. +The program accepts up to three command-line arguments. +The first argument specifies the number of seconds for +the initial expiration of the timer. +The second argument specifies the interval for the timer, in seconds. +The third argument specifies the number of times the program should +allow the timer to expire before terminating. +The second and third command-line arguments are optional. + +The following shell session demonstrates the use of the program: +.in +4n +.nf + +$ a.out 3 1 100 +0.000: timer started +3.000: read: 1; total=1 +4.000: read: 1; total=2 +[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 +[type control-C to terminate the program] +.fi +.in +.nf + +.\" FIXME . Check later what header file glibc uses for timerfd +.\" +.\" The commented out code here is what we currently need until +.\" the required stuff is in glibc +.\" +.\" +.\"/* Link with -lrt */ +.\"#define _GNU_SOURCE +.\"#include <sys/syscall.h> +.\"#include <unistd.h> +.\"#include <time.h> +.\"#if defined(__i386__) +.\"#define __NR_timerfd_create 322 +.\"#define __NR_timerfd_settime 325 +.\"#define __NR_timerfd_gettime 326 +.\"#endif +.\" +.\"static int +.\"timerfd_create(int clockid, int flags) +.\"{ +.\" return syscall(__NR_timerfd_create, clockid, flags); +.\"} +.\" +.\"static int +.\"timerfd_settime(int fd, int flags, struct itimerspec *new_value, +.\" struct itimerspec *curr_value) +.\"{ +.\" return syscall(__NR_timerfd_settime, fd, flags, new_value, +.\" curr_value); +.\"} +.\" +.\"static int +.\"timerfd_gettime(int fd, struct itimerspec *curr_value) +.\"{ +.\" return syscall(__NR_timerfd_gettime, fd, curr_value); +.\"} +.\" +.\"#define TFD_TIMER_ABSTIME (1 << 0) +.\" +.\"//////////////////////////////////////////////////////////// +.\" FIXME verify that this is the right header file in glibc +#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"); + + s = timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL); + if (s == \-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); +} +.fi +.SH "SEE ALSO" +.BR eventfd (2), +.BR poll (2), +.BR read (2), +.BR select (2), +.BR setitimer (2), +.BR signalfd (2), +.BR timer_create (3), +.BR timer_gettime (3), +.BR timer_settime (3), +.BR epoll (7), +.BR time (7) +.\" FIXME Create links for timerfd_settime.2 and timerfd_gettime.2. +.\" FIXME have SEE ALSO in setitimer.2 refer to this page. +.\" FIXME have SEE ALSO in time.7 refer to this page. |
