Semaphores in Linux Kernel
π€ Semaphores in Linux Kernel
✅ What is a semaphore?
A semaphore in Linux is a sleeping lock used to protect shared resources.
-
If the semaphore is free → the task acquires it immediately
-
If unavailable → the task is:
-
placed in a wait queue
-
put to sleep
-
CPU executes other tasks
-
-
When released → one waiting task is woken up and allowed to acquire it
π Unlike spin locks, no busy waiting occurs, so CPU time is not wasted.
✅ Why semaphores are used
Semaphores are suitable when:
✔ Lock may be held for a long time
✔ Task may need to sleep
✔ Synchronization involves user-space interaction
✔ Blocking is acceptable
They are not good for very short locks because:
-
sleeping + wakeup overhead
-
managing wait queues
can cost more than the protected operation.
✅ Important properties
1️⃣ Sleeping behavior
When a task waits:
-
it sleeps instead of spinning
-
improves CPU utilization
-
allows scheduler to run other tasks
2️⃣ Process-context only
Because semaphores may sleep:
❌ Cannot be used in interrupt handlers
✔ Must be used only in process context
(interrupt context cannot be scheduled)
3️⃣ Can sleep while holding a semaphore
Unlike spin locks:
✔ It is allowed to sleep while holding a semaphore
Other tasks requesting it:
-
simply go to sleep
-
no deadlock from spinning
4️⃣ Cannot acquire semaphore while holding spin lock
Because:
-
semaphore acquisition may sleep
-
sleeping while holding spin lock is illegal
5️⃣ Do not disable kernel preemption
Unlike spin locks:
-
code holding semaphore can be preempted
-
does not increase scheduling latency
π’ Types of Semaphores
π’ Binary semaphore (mutex)
-
Count = 1
-
Only one holder allowed
-
Used for mutual exclusion
-
Most common in kernel
π΅ Counting semaphore
-
Count > 1
-
Allows multiple simultaneous holders
-
Used to limit resource usage
-
Rarely used in kernel
⚙️ Semaphore Operations
Semaphores support two atomic operations:
⬇️ down() → acquire semaphore
-
decrements count by 1
-
if result ≥ 0 → lock acquired
-
if result < 0 → task sleeps in wait queue
This is called “downing” the semaphore
⬆️ up() → release semaphore
-
increments count
-
wakes one waiting task (if any)
Called “upping” the semaphore
π Creating and Initializing Semaphores
Static semaphore
Static mutex shortcut (binary semaphore)
Dynamic semaphore
Dynamic mutex
π Using Semaphores
Acquire (interruptible sleep)
-
sleeps in TASK_INTERRUPTIBLE
-
wakes on signal
-
returns -EINTR if interrupted
π Most commonly used
Acquire (uninterruptible sleep)
-
sleeps in TASK_UNINTERRUPTIBLE
-
ignores signals
-
usually avoided
Try acquire without blocking
-
returns immediately if unavailable
Release semaphore
Example
π Reader–Writer Semaphores
Used when:
-
many readers
-
few writers
-
read/write paths clearly separated
Characteristics
✔ Multiple readers allowed simultaneously
✔ Only one writer allowed
✔ Writers require exclusive access
All reader-writer semaphores:
-
behave like mutexes internally (count=1)
-
use uninterruptible sleep
Creating
Dynamic:
Reader usage
Writer usage
Trylock versions
Return nonzero on success (note: opposite of normal semaphore trylock).
Special feature
downgrade_write()
-
atomically converts write lock → read lock
(Not available in reader-writer spin locks)
⚖️ Spin Lock vs Semaphore (Quick comparison)
| Feature | Spin Lock | Semaphore |
|---|---|---|
| Waiting style | Busy wait (spin) | Sleep |
| CPU usage | High while waiting | Efficient |
| Use in interrupt context | ✔ Yes | ❌ No |
| Long lock hold time | ❌ Bad | ✔ Good |
| Allows sleeping inside critical section | ❌ No | ✔ Yes |
| Preemption disabled | ✔ Yes | ❌ No |
⭐ Key takeaway
π Spin lock = fast, short, cannot sleep
π Semaphore = slower, can sleep, used for longer operations
Comments
Post a Comment