SPL(9) | MidnightBSD Kernel Developer's Manual | SPL(9) |
splbio
, splclock
,
splhigh
, splimp
,
splnet
, splsoftclock
,
splsofttty
, splstatclock
,
spltty
, splvm
,
spl0
, splx
—
manipulate interrupt priorities
#include
<sys/types.h>
#include <sys/systm.h>
intrmask_t
splbio
(void);
intrmask_t
splclock
(void);
intrmask_t
splhigh
(void);
intrmask_t
splimp
(void);
intrmask_t
splnet
(void);
intrmask_t
splsoftclock
(void);
intrmask_t
splsofttty
(void);
intrmask_t
splstatclock
(void);
intrmask_t
spltty
(void);
void
spl0
(void);
void
splx
(intrmask_t
ipl);
The
spl
() function
family sets the interrupt priority “level” of the CPU. This
prevents interrupt handlers of the blocked priority level from being run.
This is used in the “synchronous” part of a driver (the part
that runs on behalf of the user process) to examine or modify data areas
that might be examined or modified by interrupt handlers.
Each driver that uses interrupts is normally assigned to an interrupt priority group by a keyword in its config line. For example:
device foo0 at isa? port 0x0815 irq 12 tty
assigns interrupt 12 to the “tty” priority
group. The system automatically arranges for interrupts in the
xxx group to be called at a priority >=
splxxx
()
The function
splx
() sets
the interrupt priority to an absolute value. The intent is that the value
returned by the other functions should be saved in a local variable, and
later passed to splx
() in order to restore the
previous priority.
The function
spl0
() lowers
the priority to a value where all interrupt handlers are unblocked, but ASTs
(asynchronous system traps) remain blocked until the system is about to
return to user mode.
The traditional assignment of the various device drivers to the interrupt priority groups can be roughly classified as:
splnet
()splimp
()splbio
()spltty
()All functions except splx
() and
spl0
() return the previous priority value.
This is a typical example demonstrating the usage:
struct foo_softc { ... int flags; #define FOO_ASLEEP 1 #define FOO_READY 2 } foo_softc[NFOO]; int foowrite(...) { struct foo_softc *sc; int s, error; ... s = spltty(); if (!(sc->flags & FOO_READY)) { /* Not ready, must sleep on resource. */ sc->flags |= FOO_ASLEEP; error = tsleep(sc, PZERO, "foordy", 0); sc->flags &= ~FOO_ASLEEP; } sc->flags &= ~FOO_READY; splx(s); ... } void foointr(...) { struct foo_softc *sc; ... sc->flags |= FOO_READY; if (sc->flags & FOO_ASLEEP) /* Somebody was waiting for us, awake him. */ wakeup(sc); ... }
The interrupt priority levels appeared in a very early version of
UNIX. They have been traditionally known by number
instead of by names, and were inclusive up to higher priority levels (i.e.,
priority 5 has been blocking everything up to level 5). This is no longer
the case in FreeBSD. The traditional name
‘level
’ for them is still reflected in
the letter ‘l
’ of the respective
functions and variables, although they are not really levels anymore, but
rather different (partially inclusive) sets of functions to be blocked
during some periods of the life of the system. The historical number scheme
can be considered as a simple linearly ordered set of interrupt priority
groups.
FreeBSD 5.0 eliminated spl entirely in favor of locking primitives which scale to more than one processor.
This manual page was written by Jörg Wunsch.
July 21, 1996 | midnightbsd-3.1 |