mirror of https://github.com/mkerrisk/man-pages
522 lines
13 KiB
Groff
522 lines
13 KiB
Groff
.\" 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-09-23 Linux "Linux Programmer's Manual"
|
|
.SH NAME
|
|
timerfd_create, timerfd_settime, timerfd_gettime \-
|
|
timers that notify via file descriptors
|
|
.SH SYNOPSIS
|
|
.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_getoverrun (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).
|
|
|
|
Starting with Linux 2.6.27, the following values may be bitwise ORed in
|
|
.IR flags
|
|
to change the behavior of
|
|
.BR timerfd_create ():
|
|
.TP 14
|
|
.B TFD_NONBLOCK
|
|
Set the
|
|
.BR O_NONBLOCK
|
|
file status flag on the new file descriptor.
|
|
Using this flag saves extra calls to
|
|
.BR fcntl ()
|
|
to achieve the same result.
|
|
.TP
|
|
.B TFD_CLOEXEC
|
|
Set the close-on-exec
|
|
.RB ( FD_CLOEXEC )
|
|
flag on the new file descriptor.
|
|
See the description of the
|
|
.B O_CLOEXEC
|
|
flag in
|
|
.BR open (2)
|
|
for reasons why this may be useful.
|
|
.PP
|
|
In Linux versions up to and including 2.6.26,
|
|
.I flags
|
|
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 non-zero 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 non-zero 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_value
|
|
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_value ).
|
|
|
|
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
|
|
structure 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 ;
|
|
.TP
|
|
.B EINVAL
|
|
.I flags
|
|
is invalid;
|
|
or, in Linux 2.6.26 or earlier,
|
|
.I flags
|
|
is non-zero.
|
|
.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.
|
|
Library support is provided by in glibc since version 2.8.
|
|
.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
|
|
|
|
.\" 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)
|
|
.\"
|
|
.\"////////////////////////////////////////////////////////////
|
|
#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);
|
|
}
|
|
.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)
|