timer_timeout(), timer_timeout_r()

Установить таймаут для состояния блокировки

Прототип:

#include <time.h>
extern int timer_timeout( clockid_t id,
int flags,
const struct sigevent *notify,
const struct timespec *ntime,
struct timespec *otime );
extern int timer_timeout_r( clockid_t id,
int flags,
const struct sigevent *notify,
const struct timespec *ntime,
struct timespec *otime );

Аргументы:

id
Тип часов таймера реализующего таймаут:
CLOCK_REALTIME
стандартные часы, определенные в POSIX. Основанные на этих часах таймеры, разбудят процессор, если он находится в режиме энергосбережения.
CLOCK_SOFTTIME
эти часы активны, когда процессор не находится в режиме энергосбережения. Например, приложение, использующее таймер на базе CLOCK_SOFTTIME для сна, не "разбудит" процессор, когда приложение должно проснуться. Это позволит процессору перейти в режим энергосбережения. Когда процессор не находится в режиме энергосбережения таймеры типа CLOCK_SOFTTIME аналогичны типу CLOCK_REALTIME.
CLOCK_MONOTONIC
эти часы всегда увеличиваются с постоянной скоростью и не могут быть отрегулированы.
flags
Битовая маска состояний блокировки, для которых будет установлен таймаут.
notify
Указатель на структуру struct sigevent, в которой задается событие - уведомление, которое будет послано ядром после истечения таймаута.
ntime
Указатель на структуру struct timespec, в которой задается таймаут.
otime
NULL, или указатель на структуру struct timespec, в которой функция сохранит оставшееся до срабатывания таймаута время.

Библиотека:

libc

Описание:

Функции timer_timeout() и timer_timeout_r() идентичны, но по разному указывают на возникшие ошибки.

Функция timer_timeout() устанавливает таймаут из параметра ntime для любого состояния блокировки. Фактический таймаут будет сохранен в параметре otime. Для функций timer_timeout() и TimerTimeout() используется разрешение времени в наносекундах, но в этих функциях отличается формат задания времени. В функции timer_timeout() используется указатель на структуру struct timespec, содержащую 2 целочисленных значения, а в функции TimerTimeout() используется указатель на тип uint64_t.

Время в параметре ntime функции TimerTimeout() также задается в наносекундах, но когда этот параметр передается в функцию TimerTimeout() время таймаута в структуре struct timespec формируется из секунд и наносекунд.

Состояния блокировки возникают в результате следующих системных вызовов:

В программе задается, для каких состояний блокировки будет задан таймаут с помощью битовой маски в параметре flags. Нужные биты определены в следующих константах:

_NTO_TIMEOUT_CONDVAR
Таймаут для состояния STATE_CONDVAR.
_NTO_TIMEOUT_JOIN
Таймаут для состояния STATE_JOIN.
_NTO_TIMEOUT_INTR
Таймаут для состояния STATE_INTR.
_NTO_TIMEOUT_MUTEX
Таймаут для состояния STATE_MUTEX.
_NTO_TIMEOUT_RECEIVE
Таймаут для состояния STATE_RECEIVE.
_NTO_TIMEOUT_REPLY
Таймаут для состояния STATE_REPLY.
_NTO_TIMEOUT_SEM
Таймаут для состояния STATE_SEM.
_NTO_TIMEOUT_SEND
Таймаут для состояния STATE_SEND.
_NTO_TIMEOUT_SIGSUSPEND
Таймаут для состояния STATE_SIGSUSPEND.
_NTO_TIMEOUT_SIGWAITINFO
Таймаут для состояния STATE_SIGWAITINFO.

Например, чтобы установить таймаут для функции MsgSendv() необходимо задать:

_NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY

В случае, если таймаут задан функцией timer_timeout(), он будет включен или отключен при следующих условиях:

Включен
Ядро устанавливает состояние блокировки, как указано в параметре flags.
Отключен
Блокируемый вызов ядра завершен без блокировки, или возникло состояние блокировки, но разблокировка произошла до истечения времени таймаута, или истекло время таймаута.

Функция timer_timeout() работает "одноразово". В случае, если блокируемый вызов ядра завершается (или прерывается сигналом), запрос на таймаут удаляется из системы. В потоке одновременно может сработать только один таймаут. Следующий вызов timer_timeout() заменит существующий таймаут в этом потоке. В случае, если значение параметра flags равно 0, таймаут не будет задан ни для какого состояния блокировки. Это значение используется по умолчанию при создании потока.

Функцию timer_timeout() необходимо вызывать непосредственно перед вызовом функции, для которой необходимо установить таймаут, например:

...
event.sigev_notify = SIGEV_UNBLOCK;
timeout.tv_sec = 10;
timeout.tv_nsec = 0;
timer_timeout( CLOCK_REALTIME, _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY,
&event, &timeout, NULL );
MsgSendv( coid, NULL, 0, NULL, 0 );
...

В случае, если между вызовами функций timer_timeout() и MsgSendv() будет вызван обработчик сигнала параметры функции timer_timeout() сохраняются во время обработки сигнала, а затем восстанавливаются при выходе из обработчика сигнала.

После срабатывания таймаута ядро посылает событие, указанное в параметре notify структуры struct sigevent. Рекомендуется использовать следующие типы событий:

SIGEV_SIGNAL
SIGEV_SIGNAL_CODE
SIGEV_SIGNAL_THREAD
SIGEV_PULSE
SIGEV_UNBLOCK
SIGEV_INTR

Только при использовании типа SIGEV_UNBLOCK гарантируется, то системный вызов будет разблокирован, поскольку сигнал может быть проигнорирован, заблокирован или принят другим потоком, а пульс может быть принят функцией MsgReceivev(). В случае, если параметр event равен NULL, будет использоваться тип события SIGEV_UNBLOCK. В данном случае при срабатывании таймаута блокируемый системный вызов завершится с ошибкой ETIMEDOUT.


Note: Функция MsgSendv() не разблокируется событием SIGEV_UNBLOCK, если сервер уже получил сообщение с помощью вызова MsgReceivev() и был установлен флаг _NTO_CHF_UNBLOCK при создании канала в функции ChannelCreate(). В этом случае сервер должен выполнить вызов MsgReplyv() или MsgError().

Особенности таймаута:


Note: В связи с особенностями измерения времени, таймер может фактически истечь позже указанного времени.

В случае, если не требуется установить таймаут не определенное время, можно установить параметр ntime в NULL. В этом случае не используется таймер и типом события является SIGEV_UNBLOCK, а при входе в состояния блокировки, определенные флагами flags, функция сразу завершится с ошибкой ETIMEDOUT. Такой подход можно использовать для приема (опроса) сообщений с помощью функции MsgReceivev(), которая будет сразу завершаться по таймауту. Более правильным вариантом является использование нескольких потоков с одним блокированном на приеме сообщений.

В случае, если в параметре flags установлено значение _NTO_TIMEOUT_NANOSLEEP, тогда системные вызовы заблокируются в состоянии до срабатывания таймаута (или получения сигнала, который разблокирует поток). Такой подход может использоваться для реализации задержки следующим образом:

timer_timeout( CLOCK_REALTIME, _NTO_TIMEOUT_NANOSLEEP, NULL, &ntime, &otime );

В случае, если параметр otime не равен NULL и задержка (sleep) будет разблокирована сигналом, то в этом параметре будет сохранено время, оставшееся до окончании задержки.

Состояния блокировки:

Данные вызовы является неблокируемыми, если в параметре flags не указано значение _NTO_TIMEOUT_NANOSLEEP, иначе вызовы блокируются следующим образом:

STATE_NANOSLEEP
Вызывающий поток блокируется на заданный период времени.

Возвращаемое значение:

timer_timeout()
Предыдущий флаг. Если возникла ошибка функция возвращает -1, код ошибки записывается в errno.
timer_timeout_r()
Предыдущий флаг. Функция НЕ устанавливает errno. При возникновении ошибки функция возвращает один из представленных ниже кодов со знаком минус.

Коды ошибок:

EAGAIN
Нет свободных системных таймеров.
EFAULT
Возникла ошибка при доступе ядра к буферам ntime, otime, или notify.
EINTR
Вызов был прерван сигналом.
EINVAL
Тип часов id не является типом CLOCK_MONOTONIC, CLOCK_SOFTTIME, или CLOCK_REALTIME.

Классификация:

ЗОСРВ «Нейтрино»

Безопасность использования
Точка остановки потока
Нет
Обработчик прерываний
Нет
Обработчик сигналов
Да
В потоке
Да

Предостережения:

Таймаут начинает отсчитываться от момента вызова функции timer_timeout(), а не при входе в состояние блокировки. Существует вероятность, что произойдет вытеснение потока после вызова timer_timeout() до перехода в состояние блокировки.

Тематические ссылки:

struct sigevent, struct timespec, TimerCreate(), TimerInfo(), TimerTimeout()




Предыдущий раздел: Описание API системной библиотеки