Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Using Spinlocks and Mutexes | Interrupts, Timing, and Concurrency
Practice
Projects
Quizzes & Challenges
Quizzes
Challenges
/
C Device Drivers Basics

bookUsing 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

spinlock_interrupt_example.c

copy
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

mutex_process_example.c

copy
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");
question mark

Which synchronization primitive should be used in interrupt context: spinlock or mutex?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 4. ChapterΒ 3

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Suggested prompts:

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?

bookUsing 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

spinlock_interrupt_example.c

copy
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

mutex_process_example.c

copy
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");
question mark

Which synchronization primitive should be used in interrupt context: spinlock or mutex?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 4. ChapterΒ 3
some-alt