Using Spinlocks and Mutexes
Spinlocks and mutexes are two fundamental synchronization primitives used in kernel development to protect shared data from concurrent access. A spinlock is a lightweight lock where a thread repeatedly checks if the lock is available, "spinning" in a tight loop until it can acquire the lock. This is efficient in short, non-blocking critical sections, especially in contexts where sleeping is not allowed, such as interrupt handlers. A mutex (short for "mutual exclusion") is a heavier-weight lock that can put the thread to sleep if the lock is not available, making it suitable for longer critical sections where sleeping is allowed, such as process context.
spinlock_interrupt_example.c
12345678910111213141516171819202122232425262728293031323334353637#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/spinlock.h> static spinlock_t my_lock; static int shared_data = 0; irqreturn_t my_interrupt_handler(int irq, void *dev_id) { unsigned long flags; // Acquire spinlock and save interrupt state spin_lock_irqsave(&my_lock, flags); shared_data++; spin_unlock_irqrestore(&my_lock, flags); return IRQ_HANDLED; } static int __init spinlock_example_init(void) { spin_lock_init(&my_lock); // Normally you would request an IRQ here and register my_interrupt_handler pr_info("Spinlock interrupt example loaded\n"); return 0; } static void __exit spinlock_example_exit(void) { pr_info("Spinlock interrupt example unloaded\n"); } module_init(spinlock_example_init); module_exit(spinlock_example_exit); MODULE_LICENSE("GPL");
You should use a spinlock, as shown in the code above, when you need to protect shared data in interrupt context or any context where sleeping is not allowed. Spinlocks are designed for short, quick operations and do not cause the current context to sleep, making them ideal for interrupt handlers. Mutexes, on the other hand, can sleep and are only safe to use in process context, where sleeping is permitted. If you try to use a mutex in an interrupt handler, you may cause a deadlock or crash, since mutexes may block the current context.
mutex_process_example.c
1234567891011121314151617181920212223242526272829303132333435363738// mutex_process_example.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/mutex.h> #include <linux/fs.h> static DEFINE_MUTEX(my_mutex); static int shared_resource = 0; ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret = 0; if (mutex_lock_interruptible(&my_mutex)) return -ERESTARTSYS; shared_resource++; mutex_unlock(&my_mutex); ret = count; return ret; } static int __init mutex_example_init(void) { pr_info("Mutex process example loaded\n"); return 0; } static void __exit mutex_example_exit(void) { pr_info("Mutex process example unloaded\n"); } module_init(mutex_example_init); module_exit(mutex_example_exit); MODULE_LICENSE("GPL");
Thanks for your feedback!
Ask AI
Ask AI
Ask anything or try one of the suggested questions to begin our chat
Can you explain the main differences between spinlocks and mutexes in more detail?
When should I use a mutex instead of a spinlock?
Are there any best practices for using spinlocks safely in kernel development?
Awesome!
Completion rate improved to 3.85
Using Spinlocks and Mutexes
Swipe to show menu
Spinlocks and mutexes are two fundamental synchronization primitives used in kernel development to protect shared data from concurrent access. A spinlock is a lightweight lock where a thread repeatedly checks if the lock is available, "spinning" in a tight loop until it can acquire the lock. This is efficient in short, non-blocking critical sections, especially in contexts where sleeping is not allowed, such as interrupt handlers. A mutex (short for "mutual exclusion") is a heavier-weight lock that can put the thread to sleep if the lock is not available, making it suitable for longer critical sections where sleeping is allowed, such as process context.
spinlock_interrupt_example.c
12345678910111213141516171819202122232425262728293031323334353637#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/spinlock.h> static spinlock_t my_lock; static int shared_data = 0; irqreturn_t my_interrupt_handler(int irq, void *dev_id) { unsigned long flags; // Acquire spinlock and save interrupt state spin_lock_irqsave(&my_lock, flags); shared_data++; spin_unlock_irqrestore(&my_lock, flags); return IRQ_HANDLED; } static int __init spinlock_example_init(void) { spin_lock_init(&my_lock); // Normally you would request an IRQ here and register my_interrupt_handler pr_info("Spinlock interrupt example loaded\n"); return 0; } static void __exit spinlock_example_exit(void) { pr_info("Spinlock interrupt example unloaded\n"); } module_init(spinlock_example_init); module_exit(spinlock_example_exit); MODULE_LICENSE("GPL");
You should use a spinlock, as shown in the code above, when you need to protect shared data in interrupt context or any context where sleeping is not allowed. Spinlocks are designed for short, quick operations and do not cause the current context to sleep, making them ideal for interrupt handlers. Mutexes, on the other hand, can sleep and are only safe to use in process context, where sleeping is permitted. If you try to use a mutex in an interrupt handler, you may cause a deadlock or crash, since mutexes may block the current context.
mutex_process_example.c
1234567891011121314151617181920212223242526272829303132333435363738// mutex_process_example.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/mutex.h> #include <linux/fs.h> static DEFINE_MUTEX(my_mutex); static int shared_resource = 0; ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret = 0; if (mutex_lock_interruptible(&my_mutex)) return -ERESTARTSYS; shared_resource++; mutex_unlock(&my_mutex); ret = count; return ret; } static int __init mutex_example_init(void) { pr_info("Mutex process example loaded\n"); return 0; } static void __exit mutex_example_exit(void) { pr_info("Mutex process example unloaded\n"); } module_init(mutex_example_init); module_exit(mutex_example_exit); MODULE_LICENSE("GPL");
Thanks for your feedback!