Locking Mechanism
Table of Contents
1 Kernel locking mechanism
The kernel provides several locking mechanisms. The most important are:
- Semaphore
- Mutex
- Spinlock
2 Mutex
The required header is include/linux/mutex.h
2.1 Mutex API
2.1.1 Declare
- Statically:
DEFINE_MUTE(my_mutex); - Dynamically:
struct mutex my_mutex;
mutex_init(&my_mutex);
2.1.2 Acquire and release
- Lock:
void mutex_lock(struct mutex *lock);
int __must_check mutex_lock_interruptible(struct mutex *lock);
int __must_check mutex_lock_killable(struct mutex *lock); - Unlock:
void mutex_unlock(struct mutex *lock);
You can use mutex_is_locked() to check whether a mutex is locked or not:
bool mutex_is_locked(struct mutex *lock);
There is also mutex_trylock(), that acquires the mutex if it is not already locked, and return1; otherwise, it returns 0:
int mutex_trylock(struct mutex *lock);
Here is an example of a muex implementation:
struct mutex my_mutex; mutex_init(&my_mutex); /* inside a work or a thread */ mutex_lock(&my_mutex); access_shared_memory(); mutex_unlock(&my_mutex);
3 Spinelock
spin_lock() and spin_lock_irqsave() are used to acquire a spinlock, all of them will disable the preemption on the process, Since spin_lock_irqsave also disable the interrupts on the CPU. If you do not know in advance what system you will write the driver for, it is recommended you acquire a spinlock using spin_lock_irqsave(), which disables interrupts on the current process before the spinlock. spin_lock_irqsave() internally calls local_irq_save().
The following is an example:
#include <linux/spinlock.h> /* some where */ spinlock_t my_spinlock; spin_lock_init(&my_spinlock); static irqreturn_t my_irq_handler(int irq, void *data) { unsigned long status, flags; spin_lock_irqsave(&my_spinlock, flags); status = access_shared_resources(); spin_unlock_irqrestore(&my_spinlock, flags); return IRQ_HANDLED; }
4 Spinlock versus mutexes
Uesd for concurrency in the kernel, spinlocks and mutexes each have their own objectives.
- Mutexes protect the process's critical resource, whereas spinlock protects the IRQ handler's critical sections.
- Mutexes put contenders to sleep until the lock is acquired, whereas spinlocks infinitely spin in a loop(consuming CPU) until the lock is acquired.
- Because of the previous poing, you can't hold spinlock for a long time, since waiters will waste CPU time waiting for the lock, whereas a mutex can be held as long as the resource needs to be protected, since contenders are put to sleep in a wait queue.