Chapter 5. Delaying Execution

image with no caption

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

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.216.229