Writing Device Drivers

Condition Variables

In the SunOS 4.1 system, when the driver needed the current process to wait for something (such as a data transfer to complete), it called sleep()(), specifying a channel and a dispatch priority. The interrupt routine then called wakeup()( ) on that channel to notify all processes waiting on that channel that something happened. Because the interrupt could occur at any time, the interrupt priority was usually raised to ensure that the wakeup could not occur until the process was asleep.


Example A-1 SunOS 4.1 Synchronization Method

int		busy; /* global device busy flag */
int xxread(dev, uio)
dev_t		dev;
struct uio *uio;
{
	int		s;
	s = splr(pritospl(6));
	while (busy)
	    	sleep(&busy, PRIBIO + 1);
	busy = 1;
	(void)splx(s);
	/* do the read */
}
int xxintr()
{
	busy = 0;
	wakeup(&busy);
}

The SunOS 5.7 system provides similar functionality with condition variables. Threads are blocked on condition variables until they are notified that the condition has occurred. The driver must acquire a mutex that protects the condition variable before blocking the thread. The mutex is then released before the thread is blocked (similar to blocking/unblocking interrupts in the SunOS 4.1 system).


Example A-2 Synchronization in SunOS 5.7 Similar to SunOS 4.1

int			busy; 			/* global device busy flag */
kmutex_t 			busy_mu;			/* mutex protecting busy flag */
kcondvar_t			busy_cv;			/* condition variable for busy flag */
static int
xxread(dev_t dev, struct uio *uiop, cred_t *credp)
{
	mutex_enter(&busy_mu);
	while (busy)
	    	cv_wait(&busy_cv, &busy_mu);
	busy = 1;
	mutex_exit(&busy_mu);
	/* do the read */
}
static u_int
xxintr(caddr_t arg)
{
	mutex_enter(&busy_mu);
	busy = 0;
	cv_broadcast(&busy_cv);
	mutex_exit(&busy_mu);
}

Like wakeup(), cv_broadcast(9F) unblocks all threads waiting on the condition variable. To wake up one thread, use cv_signal(9F) (there was no documented equivalent for cv_signal(9F) in the SunOS 4.1 system).


Note -

There is no equivalent to the dispatch priority passed to sleep()( ).


Though the sleep()() and wakeup()() calls exist, do not use them, since the result would be an MT-unsafe driver.

See "Thread Synchronization" for more information.