An Introduction to Kernel Synchronization
A common use of the atomic integer operations is to implement counters. Protecting a sole counter with a complex locking scheme is overkill, so instead developers use atomic_inc() and atomic_dec(), which are much lighter in weight.
The fact that a contended spin lock causes threads to spin (essentially wasting processor time) while waiting for the lock to become available is salient.This behavior is the point of the spin lock. It is not wise to hold a spin lock for a long time.
Later in this chapter we discuss semaphores, which provide a lock that makes the waiting thread sleep, rather than spin, when contended.
Spin Lock Methods
Spin locks can be used in interrupt handlers, whereas semaphores cannot be used because they sleep. If a lock is used in an interrupt handler, you must also disable local interrupts (interrupt requests on the current processor) before obtaining the lock
DEFINE_SPINLOCK(mr_lock);
unsigned long flags;
spin_lock_irqsave(&mr_lock, flags);
/* critical region ... */
spin_unlock_irqrestore(&mr_lock, flags);
Big Fat Rule: Locks that simply wrap code regions are hard to understand and prone to race conditions. Lock data, not code.
Spin Locks and Bottom Halves
Therefore, a sufficient number of readers can starve pending writers.This is important to keep in mind when designing your locking.
Spin locks can be used in interrupt handlers, whereas semaphores cannot be used because they sleep. If a lock is used in an interrupt handler, you must also disable local interrupts (interrupt requests on the current processor) before obtaining the lock.
Sempahore
Semaphores in Linux are sleeping locks.When a task attempts to acquire a semaphore that is unavailable, the semaphore places the task onto a wait queue and puts the task to sleep.The processor is then free to execute other code.
Because a thread of execution sleeps on lock contention, semaphores must be obtained only in process context because interrupt context is not schedulable.
Additionally,unlike spin locks, semaphores do not disable kernel preemption and, consequently, code holding a semaphore can be preempted.
A final useful feature of semaphores is that they can allow for an arbitrary number of simultaneous lock holders.
Mutex
Seeking a simpler sleeping lock, the kernel developers introduced the mutex.
Completion Variables
BKL: The Big Kernel Lock
Sequential Locks
Preemption Disabling
To prevent this, the kernel preemption code uses spin locks as markers of nonpreemptive regions. If a spin lock is held, the kernel is not preemptive.
Ordering and Barriers
The mb() call provides both a read barrier and a write barrier. No loads or stores will be reordered across a call to mb(). It is provided because a single instruction (often the
same instruction used by rmb()) can provide both the load and store barrier.