![]() |
![]() |
![]() |
Set a timeout on a blocking state
#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 );
libc
The TimerTimeout() and TimerTimeout_r() functions are identical except in the way they indicate errors. See the Returns section for details.
These kernel calls set a timeout on any kernel blocking state. These blocking states are entered as a result of the following kernel calls:
Call | Blocking state |
---|---|
InterruptWait() | STATE_INTR |
MsgReceivev() | STATE_RECEIVE |
MsgSendv() | STATE_SEND or STATE_REPLY |
SignalSuspend() | STATE_SIGSUSPEND |
SignalWaitinfo() | STATE_SIGWAITINFO |
SyncCondvarWait() | STATE_CONDVAR |
SyncMutexLock() | STATE_MUTEX |
SyncSemWait() | STATE_SEM |
ThreadJoin() | STATE_JOIN |
The user specifies which states the timeout should apply to via a bitmask passed in the flags argument. The bits are defined by the following constants:
Constant | Meaning |
---|---|
_NTO_TIMEOUT_CONDVAR | Timeout on STATE_CONDVAR. |
_NTO_TIMEOUT_JOIN | Timeout on STATE_JOIN. |
_NTO_TIMEOUT_INTR | Timeout on STATE_INTR. |
_NTO_TIMEOUT_MUTEX | Timeout on STATE_MUTEX. |
_NTO_TIMEOUT_RECEIVE | Timeout on STATE_RECEIVE. |
_NTO_TIMEOUT_REPLY | Timeout on STATE_REPLY. |
_NTO_TIMEOUT_SEM | Timeout on STATE_SEM. |
_NTO_TIMEOUT_SEND | Timeout on STATE_SEND. |
_NTO_TIMEOUT_SIGSUSPEND | Timeout on STATE_SIGSUSPEND. |
_NTO_TIMEOUT_SIGWAITINFO | Timeout on STATE_SIGWAITINFO. |
For example, to set a timeout on MsgSendv(), specify:
_NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY
Once a timeout is specified using TimerTimeout(), it's armed and released under the following conditions:
TimerTimeout() always operates on a one-shot basis. When one of the above kernel calls returns (or is interrupted by a signal), the timeout request is removed from the system. Only one timeout per thread may be in effect at a time. A second call to TimerTimeout(), without calling one of the above kernel functions, replaces the existing timeout on that thread. A call with flags set to zero ensures that a timeout won't occur on any state. This is the default when a thread is created.
Always call TimerTimeout() just before the function that you wish to timeout. For example:
... 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 ); ...
If the signal handler is called between the calls to TimerTimeout() and MsgSendv(), the TimerTimeout() values are saved during the signal handler and then are restored when the signal handler exits.
If the timeout expires, the kernel acts upon the event specified in the sigevent structure pointed to by the notify argument. We recommend the following event types in this case:
Only SIGEV_UNBLOCK guarantees that the kernel call unblocks. A signal may be ignored, blocked, or accepted by another thread and a pulse can only unblock a MsgReceivev(). If a NULL is passed for event, then SIGEV_UNBLOCK is assumed. In this case, a timed out kernel call will return failure with an error of ETIMEDOUT.
![]() |
MsgSendv() won't unblock on SIGEV_UNBLOCK if the server has already received the message via MsgReceivev() and has specified _NTO_CHF_UNBLOCK in the flags argument to its ChannelCreate() call. In this case, it's up to the server to do a MsgReplyv(). |
The type of timer used to implement the timeout is specified with the id argument.
The timeout:
( ntime ) / ( size of timer tick ) nanoseconds
If you specify a resolution that amounts to 1.7 timer ticks, you'll wake up in at least 1.7 timer ticks.
If you don't wish to block for any time, you can pass a NULL for ntime in which case no timer is used, the event is assumed to be SIGEV_UNBLOCK and an attempt to enter a blocking state as set by flags will immediately return with ETIMEDOUT. Although a questionable practice, this can be used to poll potential blocking kernel calls. For example, you can poll for messages using MsgReceivev() with an immediate timeout. A much better approach is to use multiple threads and have one block waiting for messages.
If flags is set to _NTO_TIMEOUT_NANOSLEEP, then these calls block in the STATE_NANOSLEEP state until the timeout (or a signal which unblocks the thread) occurs. This can be used to implement an efficient kernel sleep as follows:
TimerTimeout( CLOCK_REALTIME, _NTO_TIMEOUT_NANOSLEEP, NULL, ntime, otime );
If otime isn't NULL and the sleep is unblocked by a signal then it contains the time remaining in the sleep.
These calls don't block unless _NTO_TIMEOUT_NANOSLEEP is specified in flags. In this case, the calls block as follows:
The only difference between these functions is the way they indicate errors:
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
The timeout value starts timing out when TimerTimeout() is called, not when the blocking state is entered. It might be possible to get preempted after calling TimerTimeout() but before the blocking kernel call.
sigevent, TimerCreate(), TimerInfo()
![]() |
![]() |
![]() |