Kernel Functions for Drivers condvar(9F)
NAME
condvar, cvinit, cvdestroy, cvwait, cvsignal,
cvbroadcast, cvwaitsig, cvtimedwait, cvtimedwaitsig -
condition variable routines
SYNOPSIS
#include
void cvinit(kcondvart *cvp, char *name, kcvtypet type, void *arg);
void cvdestroy(kcondvart *cvp);
void cvwait(kcondvart *cvp, kmutext *mp);
void cvsignal(kcondvart *cvp);
void cvbroadcast(kcondvart *cvp);
int cvwaitsig(kcondvart *cvp, kmutext *mp);
clockt cvtimedwait(kcondvart *cvp, kmutext *mp, clockt timeout);
clockt cvtimedwaitsig(kcondvart *cvp, kmutext *mp, clockt timeout);
INTERFACE LEVEL
Solaris DI specific (Solaris DI).
PARAMETERS
cvp A pointer to an abstract data type kcondvart.
mp A pointer to a mutual exclusion lock (kmutext),
initialized by mutexinit(9F) and held by the
caller.
name Descriptive string. This is obsolete and should
be NUL. (Non-NUL strings are legal, but they're
a waste of kernel memory.)
SunOS 5.11 Last change: 15 Dec 2003 1
Kernel Functions for Drivers condvar(9F)
type The constant CVDRIVER.
arg A type-specific argument, drivers should pass arg
as NUL.
timeout A time, in absolute ticks since boot, when
cvtimedwait() or cvtimedwaitsig() should
return.
DESCRIPTION
Condition variables are a standard form of thread synchroni-
zation. They are designed to be used with mutual exclusion
locks (mutexes). The associated mutex is used to ensure that
a condition can be checked atomically and that the thread
can block on the associated condition variable without miss-
ing either a change to the condition or a signal that the
condition has changed. Condition variables must be initial-
ized by calling cvinit(), and must be deallocated by cal-
ling cvdestroy().
The usual use of condition variables is to check a condition
(for example, device state, data structure reference count,
etc.) while holding a mutex which keeps other threads from
changing the condition. If the condition is such that the
thread should block, cvwait() is called with a related con-
dition variable and the mutex. At some later point in time,
another thread would acquire the mutex, set the condition
such that the previous thread can be unblocked, unblock the
previous thread with cvsignal() or cvbroadcast(), and then
release the mutex.
cvwait() suspends the calling thread and exits the mutex
atomically so that another thread which holds the mutex can-
not signal on the condition variable until the blocking
thread is blocked. Before returning, the mutex is reac-
quired.
cvsignal() signals the condition and wakes one blocked
thread. All blocked threads can be unblocked by calling
cvbroadcast(). cvsignal() and cvbroadcast() can be called
by a thread even if it does not hold the mutex passed into
cvwait(), though holding the mutex is necessary to ensure
predictable scheduling.
SunOS 5.11 Last change: 15 Dec 2003 2
Kernel Functions for Drivers condvar(9F)
The function cvwaitsig() is similar to cvwait() but
returns 0 if a signal (for example, by kill(2)) is sent to
the thread. In any case, the mutex is reacquired before
returning.
The function cvtimedwait() is similar to cvwait(), except
that it returns -1 without the condition being signaled
after the timeout time has been reached.
The function cvtimedwaitsig() is similar to cvtimedwait()
and cvwaitsig(), except that it returns -1 without the
condition being signaled after the timeout time has been
reached, or 0 if a signal (for example, by kill(2)) is sent
to the thread.
For both cvtimedwait() and cvtimedwaitsig(), time is in
absolute clock ticks since the last system reboot. The
current time may be found by calling ddigetlbolt(9F).
RETURN VALUES
0 For cvwaitsig() and cvtimedwaitsig() indicates
that the condition was not necessarily signaled and
the function returned because a signal (as in
kill(2)) was pending.
-1 For cvtimedwait() and cvtimedwaitsig() indicates
that the condition was not necessarily signaled and
the function returned because the timeout time was
reached.
>0 For cvwaitsig(), cvtimedwait() or
cvtimedwaitsig() indicates that the condition was
met and the function returned due to a call to
cvsignal() or cvbroadcast(), or due to a prema-
ture wakeup (see NOTES).
CONTEXT
These functions can be called from user, kernel or interrupt
context. In most cases, however, cvwait(), cvtimedwait(),
cvwaitsig(), and cvtimedwaitsig() should not be called
from interrupt context, and cannot be called from a high-
level interrupt context.
If cvwait(), cvtimedwait(), cvwaitsig(), or
cvtimedwaitsig() are used from interrupt context, lower-
SunOS 5.11 Last change: 15 Dec 2003 3
Kernel Functions for Drivers condvar(9F)
priority interrupts will not be serviced during the wait.
This means that if the thread that will eventually perform
the wakeup becomes blocked on anything that requires the
lower-priority interrupt, the system will hang.
For example, the thread that will perform the wakeup may
need to first allocate memory. This memory allocation may
require waiting for paging I/O to complete, which may
require a lower-priority disk or network interrupt to be
serviced. In general, situations like this are hard to
predict, so it is advisable to avoid waiting on condition
variables or semaphores in an interrupt context.
EXAMPLES
Example 1 Waiting for a Flag Value in a Driver's Unit
Here the condition being waited for is a flag value in a
driver's unit structure. The condition variable is also in
the unit structure, and the flag word is protected by a
mutex in the unit structure.
mutexenter(&un->unlock);
while (un->unflag & UNITBUSY)
cvwait(&un->uncv, &un->unlock);
un->unflag = UNITBUSY;
mutexexit(&un->unlock);
Example 2 Unblocking Threads Blocked by the Code in Example
1
At some later point in time, another thread would execute
the following to unblock any threads blocked by the above
code.
mutexenter(&un->unlock);
un->unflag &= ~UNITBUSY;
cvbroadcast(&un->uncv);
mutexexit(&un->unlock);
NOTES
It is possible for cvwait(), cvwaitsig(), cvtimedwait(),
and cvtimedwaitsig() to return prematurely, that is, not
due to a call to cvsignal() or cvbroadcast(). This occurs
most commonly in the case of cvwaitsig() and
SunOS 5.11 Last change: 15 Dec 2003 4
Kernel Functions for Drivers condvar(9F)
cvtimedwaitsig() when the thread is stopped and restarted
by job control signals or by a debugger, but can happen in
other cases as well, even for cvwait(). Code that calls
these functions must always recheck the reason for blocking
and call again if the reason for blocking is still true.
If your driver needs to wait on behalf of processes that
have real-time constraints, use cvtimedwait() rather than
delay(9F). The delay() function calls timeout(9F), which can
be subject to priority inversions.
Not all threads can receive signals from user level
processes. In cases where such reception is impossible (such
as during execution of close(9E) due to exit(2)),
cvwaitsig() behaves as cvwait(), and cvtimedwaitsig()
behaves as cvtimedwait(). To avoid unkillable processes,
users of these functions may need to protect against waiting
indefinitely for events that might not occur. The
ddicanreceivesig(9F) function is provided to detect when
signal reception is possible.
SEE ALSO
kill(2), ddicanreceivesig(9F), ddigetlbolt(9F),
mutex(9F), mutexinit(9F)
Writing Device Drivers
SunOS 5.11 Last change: 15 Dec 2003 5
|