isters, are subject to concurrent read-modify-write
access by multiple threads and interrupt handlers.
Shared data that is operated upon by multiple
independent tasks, must be protected from context
switches such that read-modify-update operations
are not overlapped
In order to guarantee data integrity, transaction-
alized accesses are imposed on all code operating on
Kernel data objects, by means of critical sections.
A critical section estabishes a section of pro-
tected code, wherein only one task is allowed to op-
erate.
Any process executing within the boundaries of
a critical section, must exit the critical section before
another process is allowed to enter.
The critical sections boundaries serialize concur-
rent accesses to shared objects and therefore, guar-
antee that shared data and hardware register opera-
tions remain in a stable state at all times.
There are two basic classes of critical sections in
the kernel:
1. Critical Sections protecting threads from con-
current access by other threads
2. Critical Sections protecting threads from con-
current access by interrupts
3.2 Critical Section Management
Critical section management in a Linux uniproces-
sor environment is the most basic and serves as the
entry point into the discussion. In the UP environ-
ment, only a single thread of execution exists on the
CPU. The running (current) thread executes until it
relinquises the CPU voluntarily, or is interrupted by
a processor exception, such as an interrupt.
3.3 Protection from other Threads
The simplest form of critical section available in the
Linux kernel is known as a preemption-disabled sec-
tion of code. Concurrency protection from other
threads (but not interrupts) is achieved by suppress-
ing task switches while a thread is executing inside
a critical section. Task switches are suppressed by
the preempt
disable function. This Kernel design-
feature guarantees, that a thread can transition the
critical section before another thread is allowed to
execute. The requirements of the critical section
are fulfilled, since entry into a simple critical section
using the preempt disable() primitive, establishes a
non-preemptible thread execution state.
#define preempt_disable() \
do { \
inc_preempt_count(); \
barrier(); \
} while (0)
Each Linux task has a preemption counter, pre-
empt
count, in its task control structure. The
preempt disable() function increments the threads
preempt count variable. The preempt count vari-
able is allocated on a per-thread basis in the asm-
<arch>/thread info.h header file, but the value of
preempt count exerts a global effect upon the sys-
tem:
If preempt count is non-zero, task switches are
prohibited on the CPU. preempt enable() decre-
ments the preempt count variable, via the pre-
empt enable no resched() call.
#define preempt_enable() \
do { \
preempt_enable_no_resched(); \
preempt_check_resched(); \
} while (0)
Preemption may only tke place only if pre-
empt count is equal to zero.
3.3.1 Nesting of Critical Sections
It is possible for critical sections to be nested in-
side the kernel. In this case, each successive critical
section entered by the executing thread, is associ-
ated with another call to preempt disable(). The
preempt count variable tracks the nesting of criti-
cal sections, and must be decremented by a call to
preempt enable(), when a critical section is unlocked.
Only after the last critical section has been unlocked,
does the value of preempt count reach 0, indicat-
ing that the task may be preempted. In order to
achieve proper accounting of critical section nesting,
each call to preempt enable(), must thus be balanced
by a subsequent call to preempt disable().
3.4 Protection from Interrupt Han-
dlers
Critical sections demarcated by preempt disable()
and preempt enable() pairs run with interrupts en-
abled. If an interrupt occurs while a thread is exe-
cuting in a critical section, exception processing pro-
ceeds immediately, and the thread of execution is
always returned to the running thread. The current
threads preempt count is sampled upon return from
the exception, and that state determines, whether
the return from exception passes through the sched-
uler, or continues with the interrupted thread. The
code for handling interrupts while preemption is dis-
abled, is typically found in assembly code in the in-
terrupt dispatch routines located in the architecture-
specific entry.S file.
4