summaryrefslogtreecommitdiffstats
path: root/Documentation/preempt-locking.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/preempt-locking.txt')
-rw-r--r--Documentation/preempt-locking.txt135
1 files changed, 0 insertions, 135 deletions
diff --git a/Documentation/preempt-locking.txt b/Documentation/preempt-locking.txt
deleted file mode 100644
index 57883ca..0000000
--- a/Documentation/preempt-locking.txt
+++ /dev/null
@@ -1,135 +0,0 @@
- Proper Locking Under a Preemptible Kernel:
- Keeping Kernel Code Preempt-Safe
- Robert Love <rml@tech9.net>
- Last Updated: 28 Aug 2002
-
-
-INTRODUCTION
-
-
-A preemptible kernel creates new locking issues. The issues are the same as
-those under SMP: concurrency and reentrancy. Thankfully, the Linux preemptible
-kernel model leverages existing SMP locking mechanisms. Thus, the kernel
-requires explicit additional locking for very few additional situations.
-
-This document is for all kernel hackers. Developing code in the kernel
-requires protecting these situations.
-
-
-RULE #1: Per-CPU data structures need explicit protection
-
-
-Two similar problems arise. An example code snippet:
-
- struct this_needs_locking tux[NR_CPUS];
- tux[smp_processor_id()] = some_value;
- /* task is preempted here... */
- something = tux[smp_processor_id()];
-
-First, since the data is per-CPU, it may not have explicit SMP locking, but
-require it otherwise. Second, when a preempted task is finally rescheduled,
-the previous value of smp_processor_id may not equal the current. You must
-protect these situations by disabling preemption around them.
-
-You can also use put_cpu() and get_cpu(), which will disable preemption.
-
-
-RULE #2: CPU state must be protected.
-
-
-Under preemption, the state of the CPU must be protected. This is arch-
-dependent, but includes CPU structures and state not preserved over a context
-switch. For example, on x86, entering and exiting FPU mode is now a critical
-section that must occur while preemption is disabled. Think what would happen
-if the kernel is executing a floating-point instruction and is then preempted.
-Remember, the kernel does not save FPU state except for user tasks. Therefore,
-upon preemption, the FPU registers will be sold to the lowest bidder. Thus,
-preemption must be disabled around such regions.
-
-Note, some FPU functions are already explicitly preempt safe. For example,
-kernel_fpu_begin and kernel_fpu_end will disable and enable preemption.
-However, math_state_restore must be called with preemption disabled.
-
-
-RULE #3: Lock acquire and release must be performed by same task
-
-
-A lock acquired in one task must be released by the same task. This
-means you can't do oddball things like acquire a lock and go off to
-play while another task releases it. If you want to do something
-like this, acquire and release the task in the same code path and
-have the caller wait on an event by the other task.
-
-
-SOLUTION
-
-
-Data protection under preemption is achieved by disabling preemption for the
-duration of the critical region.
-
-preempt_enable() decrement the preempt counter
-preempt_disable() increment the preempt counter
-preempt_enable_no_resched() decrement, but do not immediately preempt
-preempt_check_resched() if needed, reschedule
-preempt_count() return the preempt counter
-
-The functions are nestable. In other words, you can call preempt_disable
-n-times in a code path, and preemption will not be reenabled until the n-th
-call to preempt_enable. The preempt statements define to nothing if
-preemption is not enabled.
-
-Note that you do not need to explicitly prevent preemption if you are holding
-any locks or interrupts are disabled, since preemption is implicitly disabled
-in those cases.
-
-But keep in mind that 'irqs disabled' is a fundamentally unsafe way of
-disabling preemption - any spin_unlock() decreasing the preemption count
-to 0 might trigger a reschedule. A simple printk() might trigger a reschedule.
-So use this implicit preemption-disabling property only if you know that the
-affected codepath does not do any of this. Best policy is to use this only for
-small, atomic code that you wrote and which calls no complex functions.
-
-Example:
-
- cpucache_t *cc; /* this is per-CPU */
- preempt_disable();
- cc = cc_data(searchp);
- if (cc && cc->avail) {
- __free_block(searchp, cc_entry(cc), cc->avail);
- cc->avail = 0;
- }
- preempt_enable();
- return 0;
-
-Notice how the preemption statements must encompass every reference of the
-critical variables. Another example:
-
- int buf[NR_CPUS];
- set_cpu_val(buf);
- if (buf[smp_processor_id()] == -1) printf(KERN_INFO "wee!\n");
- spin_lock(&buf_lock);
- /* ... */
-
-This code is not preempt-safe, but see how easily we can fix it by simply
-moving the spin_lock up two lines.
-
-
-PREVENTING PREEMPTION USING INTERRUPT DISABLING
-
-
-It is possible to prevent a preemption event using local_irq_disable and
-local_irq_save. Note, when doing so, you must be very careful to not cause
-an event that would set need_resched and result in a preemption check. When
-in doubt, rely on locking or explicit preemption disabling.
-
-Note in 2.5 interrupt disabling is now only per-CPU (e.g. local).
-
-An additional concern is proper usage of local_irq_disable and local_irq_save.
-These may be used to protect from preemption, however, on exit, if preemption
-may be enabled, a test to see if preemption is required should be done. If
-these are called from the spin_lock and read/write lock macros, the right thing
-is done. They may also be called within a spin-lock protected region, however,
-if they are ever called outside of this context, a test for preemption should
-be made. Do note that calls from interrupt context or bottom half/ tasklets
-are also protected by preemption locks and so may use the versions which do
-not check preemption.