Системный вызов timerfd_gettime() возвращает интервал и время, оставшееся до срабатывания часов, на которые ссылается файловый дескриптор fd.

#include

int timerfd_gettime(int fd, struct itimerspec *curr_value);

Возвращает 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.

Взаимодействие интерфейса timerfd с вызовами fork() и exec()

Во время вызова fork() дочерний процесс наследует копии файловых дескрипторов, созданных с помощью операции timerfd_create(). Эти дескрипторы ссылаются на те же объекты таймеров, которые используются родителем, а момент их срабатывания может быть прочитан любым из двух процессов.

Файловые дескрипторы, созданные с помощью операции timerfd_create(), сохраняются на протяжении работы вызова exec() (разве что они помечены флагом FD_CLOEXEC, как описано в разделе 27.4), а запущенные таймеры продолжат срабатывать даже после завершения этого вызова.

Чтение из файлового дескриптора timerfd

Запустив таймер с помощью вызова 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

Нажимаем Ctrl+Z, чтобы отправить программу в фоновый режим на несколько секунд

[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

Нажимаем Ctrl+C, чтобы завершить программу

Выше можно видеть, что во время пребывания программы в фоновом режиме произошло несколько срабатываний, каждое из которых было возвращено операцией read() после возобновления работы программы.

Листинг 23.8. Использование программного интерфейса timerfd

timers/demo_timerfd.c

#include

#include

Перейти на страницу:

Похожие книги