Condition variables are a standard form of thread synchronization. They are designed to be used with 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 missing either a change to the condition or a signal that the condition has changed.
The condvar(9F) functions are:
Signals all threads waiting on the condition variable.
Destroys a condition variable.
Initializes a condition variable.
Signals one thread waiting on the condition variable.
Waits for condition, time-out, or signal. See Threads Unable to Receive Signals.
Waits for condition or time-out.
Waits for condition.
Waits for condition or return zero on receipt of a signal. See Threads Unable to Receive Signals.
Declare a condition variable of type kcondvar_t for each condition. Usually, the condition variables are declared in the driver's soft-state structure. Use cv_init(9F) to initialize each condition variable. Similar to mutexes, condition variables are usually initialized at attach(9E) time. A typical example of initializing a condition variable is:
cv_init(&xsp->cv, NULL, CV_DRIVER, NULL);
For a more complete example of condition variable initialization, see Chapter 6, Driver Autoconfiguration.
To use condition variables, follow these steps in the code path waiting for the condition:
Acquire the mutex guarding the condition.
Test the condition.
If the test results do not allow the thread to continue, use cv_wait(9F) to block the current thread on the condition. The cv_wait(9F) function releases the mutex before blocking the thread and reacquires the mutex before returning. On return from cv_wait(9F), repeat the test.
After the test allows the thread to continue, set the condition to its new value. For example, set a device flag to busy.
Release the mutex.
Follow these steps in the code path to signal the condition:
Acquire the mutex guarding the condition.
Set the condition.
Signal the blocked thread with cv_broadcast(9F).
Release the mutex.
The following example uses a busy flag along with mutex and condition variables to force the read(9E) routine to wait until the device is no longer busy before starting a transfer.
static int xxread(dev_t dev, struct uio *uiop, cred_t *credp) { struct xxstate *xsp; /* ... */ mutex_enter(&xsp->mu); while (xsp->busy) cv_wait(&xsp->cv, &xsp->mu); xsp->busy = 1; mutex_exit(&xsp->mu); /* perform the data access */ } static uint_t xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; mutex_enter(&xsp->mu); xsp->busy = 0; cv_broadcast(&xsp->cv); mutex_exit(&xsp->mu); }