Установить таймаут для состояния блокировки
#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 );
CLOCK_SOFTTIME
для сна, не "разбудит" процессор, когда приложение должно проснуться. Это позволит процессору перейти в режим энергосбережения. Когда процессор не находится в режиме энергосбережения таймеры типа CLOCK_SOFTTIME
аналогичны типу CLOCK_REALTIME
. NULL
, Указатель на структуру struct sigevent, в которой задается событие - уведомление, которое будет послано ядром после истечения таймаута.NULL
, или указатель на переменную, в которой функция сохранит оставшееся до срабатывания таймаута время.libc
Системные вызовы TimerTimeout() и TimerTimeout_r() устанавливают таймауты для состояний блокировки ядром.
Данные функции идентичны, но по разному указывают на возникшие ошибки.
Состояния блокировки возникают в результате следующих системных вызовов:
STATE_INTR
STATE_RECEIVE
STATE_SEND
или STATE_REPLY
STATE_SIGSUSPEND
STATE_SIGWAITINFO
STATE_CONDVAR
STATE_MUTEX
STATE_SEM
STATE_JOIN
Типы таймаутов
В программе задается, для каких состояний блокировки будет задан таймаут с помощью битовой маски в параметре flags. Нужные биты определены в следующих константах:
STATE_CONDVAR
. STATE_JOIN
. STATE_INTR
. STATE_MUTEX
. STATE_RECEIVE
. STATE_REPLY
. STATE_SEM
. STATE_SEND
. STATE_SIGSUSPEND
. STATE_SIGWAITINFO
. Например, чтобы установить таймаут для функции MsgSendv() необходимо задать:
_NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY
В случае, если таймаут задан функцией timer_timeout(), он будет включен или отключен при следующих условиях:
Функция 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_UNBLOCK
гарантируется, то системный вызов будет разблокирован, поскольку сигнал может быть проигнорирован, заблокирован или принят другим потоком, а пульс может быть принят функцией MsgReceivev(). В случае, если параметр event равен NULL
, будет использоваться тип события SIGEV_UNBLOCK
. В данном случае при срабатывании таймаута блокируемый системный вызов завершится с ошибкой ETIMEDOUT
.
Функция MsgSendv() не разблокируется событием SIGEV_UNBLOCK , если сервер уже получил сообщение с помощью вызова MsgReceivev() и был установлен флаг _NTO_CHF_UNBLOCK при создании канала в функции ChannelCreate(). В этом случае сервер должен выполнить вызов MsgReplyv() или MsgError(). |
Особенности таймаута:
TIMER_ABSTIME
, при котором таймаут наступает в "абсолютное" время, определенное в ntime параметре.
1000000000
+ tv_nsec) / (значение системного тика) наносекунд.
<time.h>
).
В связи с особенностями измерения времени, таймер может фактически истечь позже указанного времени. |
В случае, если не требуется установить таймаут не определенное время, можно установить параметр 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
, иначе вызов блокируется следующим образом:
-1
, код ошибки записывается в errno.
ЗОСРВ «Нейтрино»
Таймаут начинает отсчитываться от момента вызова функции TimerTimeout(), а не при входе в состояние блокировки. Существует вероятность, что произойдет вытеснение потока после вызова TimerTimeout() до перехода в состояние блокировки.
struct sigevent, timer_timeout(), TimerCreate(), TimerInfo(), struct timespec
Предыдущий раздел: Описание API системной библиотеки