TimerTimeout(), TimerTimeout_r()

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

Прототип:

#include <sys/neutrino.h>
int TimerTimeout( clockid_t id,
int flags,
const struct sigevent *notify,
const uint64_t *ntime,
uint64_t *otime );
int TimerTimeout_r( clockid_t id,
int flags,
const struct sigevent *notify,
const uint64_t *ntime,
uint64_t *otime );

Аргументы:

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

Библиотека:

libc

Описание:

Системные вызовы TimerTimeout() и TimerTimeout_r() устанавливают таймауты для состояний блокировки ядром.

Данные функции идентичны, но по разному указывают на возникшие ошибки.


Note: Рекомендуется использовать функцию timer_timeout() вместо прямых системных вызовов.

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

Типы таймаутов

В программе задается, для каких состояний блокировки будет задан таймаут с помощью битовой маски в параметре 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.
Отключен
Блокируемый вызов ядра завершен без блокировки, или возникло состояние блокировки, но разблокировка произошла до истечения времени таймаута, или истекло время таймаута.

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

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

...
event.sigev_notify = SIGEV_UNBLOCK;
timeout = 10×1000000000;
TimerTimeout( CLOCK_REALTIME, _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY,
&event, &timeout, NULL );
MsgSendv( coid, NULL, 0, NULL, 0 );
...

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

Типы событий

После срабатывания таймаута ядро посылает событие, указанное в параметре 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) будет разблокирована сигналом, то в этом параметре будет сохранено время, оставшееся до окончании задержки.

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

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

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

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

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

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

Коды ошибок:

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

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

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

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

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

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

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

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




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