NAME
spl,
spl0,
splhigh,
splvm,
splbio,
splnet,
spltty,
splsched,
splsoftbio,
splsoftclock,
splsoftnet,
splsoftserial,
splx —
modify system interrupt
priority level
SYNOPSIS
#include <sys/intr.h>
void
spl0(
void);
int
splhigh(
void);
int
splsched(
void);
int
splvm(
void);
int
splbio(
void);
int
splnet(
void);
int
spltty(
void);
int
splsoftbio(
void);
int
splsoftclock(
void);
int
splsoftserial(
void);
int
splsoftnet(
void);
void
splx(
int
s);
DESCRIPTION
These functions raise and lower the interrupt priority level. They are used by
kernel code to block interrupts in critical sections, in order to protect data
structures.
In a multi-CPU system, these functions change the interrupt priority level on
the local CPU only. In general, device drivers should not make use of these
interfaces. To ensure correct synchronization, device drivers should use the
condvar(9),
mutex(9), and
rwlock(9) interfaces.
Interrupt priorities are arranged in a strict hierarchy, although sometimes
levels may be equivalent (overlap). The hierarchy means that raising the IPL
to any level will block interrupts at that level, and at all lower levels. The
hierarchy is used to minimize data loss due to interrupts not being serviced
in a timely fashion.
The levels may be divided into two groups: hard and soft. Hard interrupts are
generated by hardware devices. Soft interrupts are a way of deferring hardware
interrupts to do more expensive processing at a lower interrupt priority, and
are explicitly scheduled by the higher-level interrupt handler. Software
interrupts are further described by
softint(9).
Note that hard interrupt handlers do not possess process (thread) context and so
it is not valid to use kernel facilities that may attempt to sleep from a
hardware interrupt. For example, it is not possible to acquire a reader/writer
lock from a hardware interrupt. Soft interrupt handlers possess limited
process context and so may sleep briefly in order to acquire a reader/writer
lock or adaptive mutex, but may not sleep for any other reason.
In order of highest to lowest priority, the priority-raising functions along
with their counterpart symbolic tags are:
-
-
- splhigh(),
IPL_HIGH
-
Blocks all hard and soft interrupts, including the highest level I/O
interrupts, such as interrupts from serial interfaces and the statistics
clock (if any). It is also used for code that cannot tolerate any
interrupts.
Code running at this level may not (in general) directly access machine
independent kernel services. For example, it is illegal to call the kernel
printf() function or to try and allocate memory. The
methods of synchronization available are: spin mutexes and scheduling a
soft interrupt. Generally, all code run at this level must schedule
additional processing to run in a software interrupt.
Code with thread context running at this level must not use a kernel
interface that may cause the current LWP to sleep, such as the
condvar(9) interfaces.
Interrupt handlers at this level cannot acquire the global kernel_lock and
so must be coded to ensure correct synchronization on multiprocessor
systems.
-
-
- splsched(),
IPL_SCHED
-
Blocks all medium priority hardware interrupts, such as interrupts from
audio devices, and the clock interrupt.
Interrupt handlers running at this level endure the same restrictions as at
IPL_HIGH, but may access scheduler interfaces, and so may awaken LWPs
(light weight processes) using the
condvar(9) interfaces, and
may schedule callouts using the
callout(9) interfaces.
Code with thread context running at this level may sleep via the
condvar(9) interfaces, and
may use other kernel facilities that could cause the current LWP to
sleep.
-
-
- splvm(),
IPL_VM
-
Blocks hard interrupts from “low” priority hardware interrupts,
such as interrupts from network, block I/O and tty devices.
Code running at this level endures the same restrictions as at IPL_SCHED,
but may use the deprecated
malloc(9) or endorsed
pool_cache(9) interfaces
to allocate memory.
At the time of writing, the global
kernel_lock
is
automatically acquired for interrupts at this level, in order to support
device drivers that do not provide their own multiprocessor
synchronization. A future release of the system may allow the automatic
acquisition of kernel_lock
to be disabled for
individual interrupt handlers.
splbio(), splnet(), and
spltty() are synonyms for splvm().
Their use is deprecated; all new code should use
splvm().
-
-
- splsoftserial(),
IPL_SOFTSERIAL
-
Blocks soft interrupts at the IPL_SOFTSERIAL symbolic level.
This is the first of the software levels. Soft interrupts at this level and
lower may acquire reader/writer locks or adaptive mutexes.
-
-
- splsoftnet(),
IPL_SOFTNET
-
Blocks soft interrupts at the IPL_SOFTNET symbolic level.
-
-
- splsoftbio(),
IPL_SOFTBIO
-
Blocks soft interrupts at the IPL_SOFTBIO symbolic level.
-
-
- splsoftclock(),
IPL_SOFTCLOCK
-
Blocks soft interrupts at the IPL_SOFTCLOCK symbolic level.
This is the priority at which callbacks generated by the
callout(9) facility
runs.
One function lowers the system priority level:
-
-
- spl0(),
IPL_NONE
-
Unblocks all interrupts. This should rarely be used directly;
splx() should be used instead.
The
splx() function restores the system priority level to the
one encoded in
s, which must be a value previously
returned by one of the other
spl functions.
SEE ALSO
condvar(9),
i386/splraise(9),
kpreempt(9),
mutex(9),
rwlock(9)
HISTORY
In
4.4BSD,
splnet() was used to block
network software interrupts. Most device drivers used
splimp() to block hardware interrupts. To avoid
unnecessarily blocking other interrupts, in
NetBSD 1.1
a new function was added that blocks only network hardware interrupts. For
consistency with other
spl functions, the old
splnet() function was renamed to
splsoftnet(), and the new function was named
splnet().
Originally,
splsoftclock() lowered the system priority level.
During the
NetBSD 1.5 development cycle,
spllowersoftclock() was introduced and the semantics of
splsoftclock() were changed.
The
splimp() call was removed from the kernel between
NetBSD 1.5 and
NetBSD 1.6. The
function of
splimp() was replaced by
splvm() and code which abused the semantics of
splimp() was changed to not mix interrupt priority levels.
Between
NetBSD 4.0 and
NetBSD
5.0, the hardware levels were reduced in number and a strict hierarchy
defined.