Part 4: Concurrency and Synchronization
The Linux kernel is inherently concurrent - multiple CPUs, interrupts, and preemption mean your code can be interrupted or run simultaneously at any time. Understanding synchronization primitives is essential for writing correct, safe drivers.
Why Concurrency Matters
flowchart TD
subgraph Sources["Concurrency Sources"]
direction TB
SMP["Multiple CPUs"]
INT["Interrupts"]
PRE["Preemption"]
SOFT["Softirqs/Tasklets"]
end
subgraph Problem["The Problem"]
direction TB
Race["Race Conditions"]
Corrupt["Data Corruption"]
Dead["Deadlocks"]
end
subgraph Solutions["Solutions"]
direction TB
Spin["Spinlocks"]
Mutex["Mutexes"]
Atomic["Atomic Operations"]
RCU["RCU"]
end
Sources --> Problem
Problem --> Solutions
style Problem fill:#8f6d72,stroke:#c62828
style Solutions fill:#7a8f73,stroke:#2e7d32
Chapter Contents
| Chapter | Topic | Key Concepts |
|---|---|---|
| 4.1 | Concurrency Concepts | Race conditions, critical sections |
| 4.2 | Spinlocks | spin_lock, spin_lock_irqsave |
| 4.3 | Mutexes | Sleeping locks, mutex vs spinlock |
| 4.4 | Semaphores | Counting semaphores |
| 4.5 | Atomic Operations | atomic_t, bitwise atomics |
| 4.6 | RCU | Read-Copy-Update |
| 4.7 | Completions | Signaling between threads |
| 4.8 | Work Queues | Deferred processing |
| 4.9 | Lockdep | Deadlock detection |
| 4.10 | Kernel Timers | timer_list, hrtimer |
| 4.11 | Wait Queues | wait_event, wake_up |
| 4.12 | Kernel Threads | kthread_run, kthread_stop |
Quick Reference: Choosing a Lock
flowchart TD
Start["Need to protect data?"]
Sleep{"Can you sleep?"}
Duration{"Short critical section?"}
Read{"Mostly reads?"}
Counter{"Simple counter?"}
Start --> Sleep
Sleep -->|"No (interrupt context)"| Spin["Spinlock"]
Sleep -->|"Yes (process context)"| Duration
Duration -->|"Yes"| Spin
Duration -->|"No"| Mutex["Mutex"]
Sleep -->|"Yes"| Read
Read -->|"Yes, rare writes"| RCU["RCU"]
Sleep -->|"Yes"| Counter
Counter -->|"Yes"| Atomic["atomic_t"]
style Spin fill:#8f8a73,stroke:#f9a825
style Mutex fill:#738f99,stroke:#0277bd
style RCU fill:#8f7392,stroke:#6a1b9a
style Atomic fill:#7a8f73,stroke:#2e7d32
| Primitive | Sleep OK? | Interrupt Safe? | Best For |
|---|---|---|---|
| Spinlock | No | With irqsave | Short critical sections |
| Mutex | Yes | No | Longer critical sections |
| Semaphore | Yes | No | Resource counting |
| atomic_t | N/A | Yes | Simple counters |
| RCU | Read: Yes | Read: Yes | Read-heavy data |
| Completion | Yes | No | Thread synchronization |
Examples
This part includes working examples:
- spinlock-demo: Spinlock usage patterns
- workqueue-demo: Deferred work processing
- timer-demo: Kernel timer and hrtimer usage
- kthread-demo: Background kernel threads
Common Pitfalls
Deadlocks: Taking locks in different orders across code paths
Priority inversion: Low-priority task holds lock needed by high-priority task
Sleeping with spinlock: Calling functions that might sleep while holding a spinlock
Prerequisites
Before starting this part, ensure you understand:
- Process vs interrupt context (Part 2)
- Basic module structure (Part 1-2)
- Character device operations (Part 3)
Further Reading
- Locking Documentation - Kernel locking guide
- RCU Documentation - RCU concepts and API
- Workqueue Documentation - Work queue API
- Timer Documentation - Kernel timers
- Kthread Documentation - Kernel threads
Next
Start with Concurrency Concepts to understand why synchronization is necessary.