Often, drivers need to delay their execution in order to give their device(s), the kernel, or a user the time to accomplish some task. In this chapter, I’ll detail the different functions available for achieving these delays. In the process, I’ll also describe asynchronous code execution.
Voluntary context switching, or sleeping, is done when a driver thread must await the availability of a resource or the arrival of an event; for example, a driver thread should sleep after it requests data from an input device, such as a terminal (McKusick and Neville-Neil, 2005). A driver thread sleeps by calling a *sleep
function.
#include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> int tsleep(void *chan, int priority, const char *wmesg, int timo); void wakeup(void *chan); void wakeup_one(void *chan); void pause(const char *wmesg, int timo); #include <sys/param.h> #include <sys/lock.h> #include <sys/mutex.h> int mtx_sleep(void *chan, struct mtx *mtx, int priority, const char *wmesg, int timo); #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> int msleep_spin(void *chan, struct mtx *mtx, const char *wmesg, int timo); #include <sys/param.h> #include <sys/lock.h> #include <sys/sx.h> int sx_sleep(void *chan, struct sx *sx, int priority, const char *wmesg, int timo); #include <sys/param.h> #include <sys/lock.h> #include <sys/rwlock.h> int rw_sleep(void *chan, struct rwlock *rw, int priority, const char *wmesg, int timo);
A thread voluntarily context switches (or sleeps) by calling tsleep
. The arguments for tsleep
are common to the other *sleep
functions and are described in the next few paragraphs.
The chan
argument is the channel (that is to say, an arbitrary address) that uniquely identifies the event that the thread is waiting for.
The priority
argument is the priority for the thread when it resumes. If priority
is 0
, the current thread priority is used. If PCATCH
is OR
’ed into priority
, signals are checked before and after sleeping.
The wmesg
argument expects a concise description of the sleeping thread. This description is displayed by user-mode utilities, such as ps(1)
, and has no real impact on performance.
The timo
argument specifies the sleep timeout. If timo
is nonzero, the thread will sleep for at most timo
/ hz
seconds. Afterward, tsleep
returns the error code EWOULDBLOCK
.
The wakeup
function wakes up every thread asleep on the channel chan
. Generally speaking, threads woken from sleep should re-evaluate the conditions they slept on.
The wakeup_one
function is a variant of wakeup
that only gets up the first thread that it finds asleep on chan. The assumption is that when the awakened thread is done, it calls wakeup_one
to wake up another thread that’s asleep on chan
; this succession of wakeup_one
calls continues until every thread asleep on chan
has been awakened (McKusick and Neville-Neil, 2005). This reduces the load in cases when numerous threads are asleep on chan
, but only one thread can do anything meaningful when made runnable.
The pause
function puts the calling thread to sleep for timo
/ hz
seconds. This thread cannot be awoken by wakeup
, wakeup_one
, or signals.
The remaining *sleep
functions—mtx_sleep
, msleep_spin
, sx_sleep
, and rw_
sleep—are variants of tsleep that take a particular lock. This lock is dropped before the thread sleeps and is reacquired before the thread awakes; if PDROP
is OR
’ed into priority
, this lock is not reacquired.
Note that the msleep_spin
function does not have a priority
argument. Consequently, it cannot assign a new thread priority, catch signals via PCATCH
, or drop its spin mutex via PDROP
.
18.117.216.229