Системный вызов timerfd_gettime() возвращает интервал и время, оставшееся до срабатывания часов, на которые ссылается файловый дескриптор fd.
#include
int timerfd_gettime(int
Возвращает 0 при успешном завершении или –1, если случилась ошибка
Как и в случае с вызовом timer_gettime(), интервал и время, оставшееся до срабатывания таймера, возвращаются внутри структуры itimerspec, на которую указывает аргумент curr_value. Поле curr_value.it_value определяет, сколько осталось до следующего срабатывания, даже если таймер был сделан абсолютным с помощью константы TFD_TIMER_ABSTIME. Если оба поля итоговой структуры curr_value.it_value равны 0, значит, таймер выключен. Если оба поля итоговой структуры curr_value.it_interval равны 0, это говорит о том, что таймер сработал лишь раз — в момент, указанный в curr_value.it_value.
Во время вызова fork() дочерний процесс наследует копии файловых дескрипторов, созданных с помощью операции timerfd_create(). Эти дескрипторы ссылаются на те же объекты таймеров, которые используются родителем, а момент их срабатывания может быть прочитан любым из двух процессов.
Файловые дескрипторы, созданные с помощью операции timerfd_create(), сохраняются на протяжении работы вызова exec() (разве что они помечены флагом FD_CLOEXEC, как описано в разделе 27.4), а запущенные таймеры продолжат срабатывать даже после завершения этого вызова.
Запустив таймер с помощью вызова timerfd_settime(), мы можем использовать операцию read() для чтения информации о срабатываниях этого таймера из соответствующего файлового дескриптора. При этом буфер, который передается операции read(), должен быть достаточно большим, чтобы вместить 8-битное целое число (uint64_t).
Если с момента последнего изменения параметров таймера с помощью вызова timerfd_settime() или last read() он сработал один или несколько раз, операция read() немедленно завершается, а в буфер попадает количество произошедших срабатываний. Если срабатываний не было, чтение блокируется, пока таймер не сработает. Мы можем также установить дескриптору неблокирующий флаг O_NONBLOCK, воспользовавшись операцией fcntl() F_SETFL (см. раздел 5.3), чтобы при отсутствии срабатываний чтение не блокировалось, а сразу же завершалось ошибкой EAGAIN.
Как уже говорилось ранее, файловый дескриптор timerfd можно отслеживать с помощью вызовов select() и poll(), а также интерфейса epoll. При срабатывании таймера дескриптор становится доступным для чтения.
Пример использования программного интерфейса timerfd показан в листинге 23.8. Эта программа принимает два аргумента командной строки. Первый является обязательным; он обозначает начальное время и интервал таймера (он интерпретируется с помощью функции itimerspecFromStr(), представленной в листинге 23.6). Второй аргумент определяет максимальное количество срабатываний таймера, которого должна дождаться программа, прежде чем завершиться; если его опустить, будет использоваться значение 1.
Программа создает и запускает таймер, обращаясь к вызовам timerfd_create() и соответственно timerfd_settime(). Затем она входит в цикл, считывая из файлового дескриптора уведомления о срабатываниях, пока их количество не достигнет заданного значения. После каждой операции read() программа выводит время, прошедшее с момента запуска таймера, количество обнаруженных срабатываний и общее число срабатываний на текущий момент.
В следующей сессии командной строки указывается два аргумента: начальное значение и интервал таймера, равные 1 секунде, а также максимальное количество срабатываний, равное 100.
$ ./demo_timerfd 1:1 100
1.000: expirations read: 1; total=1
2.000: expirations read: 1; total=2
3.000: expirations read: 1; total=3
[1]+ Stopped./demo_timerfd 1:1 100
$ fg Resume program in foreground
./demo_timerfd 1:1 100
14.205: expirations read: 11; total=14
15.000: expirations read: 1; total=15
16.000: expirations read: 1; total=16
Выше можно видеть, что во время пребывания программы в фоновом режиме произошло несколько срабатываний, каждое из которых было возвращено операцией read() после возобновления работы программы.
Листинг 23.8. Использование программного интерфейса timerfd
timers/demo_timerfd.c
#include
#include