7

Possible Duplicate:
Why can't you sleep while holding spinlock?

As far as I know, spinlocks should be used in short duration, and are only choices in code such as interrupt handler where sleeping (preemption) is not allowed.

However, I do not know why there is such a "rule" that there SHOULD BE no sleeping at all while holding a spinlock. I know that it is not a recommended practice (since it is detrimental in performance), but I see no reason why sleeps SHOULD NOT be allowed in spinlocks.

You cannot hold a spin lock while you acquire a semaphore, because you might have to sleep while waiting for the semaphore, and you cannot sleep while holding a spin lock (from "Linux Kernel Development" by Robert Love).

The only reason I can see is for portability reasons, because in uniprocessors, spinlocks are implemented as disabling interrupts, and by disabling interrupts, sleeping is of course not allowed (but sleeping will not break code in SMP systems).

But I am wondering if my reasoning is correct or if there are any other reasons.

Community
  • 1
  • 1
SHH
  • 3,226
  • 1
  • 28
  • 41

3 Answers3

15

There are several reasons why, at least in Linux, sleeping in spinlocks is not allowed:

  1. If thread A sleeps in a spinlock, and thread B then tries to acquire the same spinlock, a uniprocessor system will deadlock. Thread B will never go to sleep (because spinlocks don't have the waitlist necessary to awaken B when A is done), and thread A will never get a chance to wake up.
  2. Spinlocks are used over semaphores precisely because they're more efficient - provided you do not contend for long. Allowing sleeping means that you will have long contention periods, erasing all the benefit of using a spinlock. Your system would be faster just using a semaphore in this case.
  3. Spinlocks are often used to synchronize with interrupt handlers, by additionally disabling interrupts. This use case is not possible if you sleep (once you enter the interrupt handler, you cannot switch back to the thread to let it wake up and finish its spinlock critical section).

Use the right tool for the right job - if you need to sleep, semaphores and mutexes are your friends.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • 1
    Actually semaphores really should not be used in kernel code unless you have a very specialized use case (really if you're reading this question on stackoverflow, you don't need semaphores :) Just use mutexes for locking when you need to sleep, and spinlocks when you need to lock in a non-sleepable context. – Roland Oct 24 '11 at 13:15
  • @bdonlan I have a doubt regarding point 1. You have said that the thread A will never wake up? Why is that? When the time slice for thread B will finish and sleep time for thread would have ended, thread A would execute using its time slice and once done will release the lock. Is it not the case? – Sumit Trehan Sep 20 '14 at 17:01
  • 3
    @SumitTrehan: Good point. If the spinlock is not something essential to the scheduler itself, and thread B was not in interrupt context and did not have interrupts or preemption disabled, then eventually thread B could be preempted. However, in linux, preemption is always disabled when a spinlock is held (or about to be held). This is because if a thread is holding a spinlock while not running, other threads waste lots of time spinning on the lock, and there is potential for deadlock with interrupt handlers. So in reality thread B won't be preemptible and will deadlock. – bdonlan Dec 08 '14 at 06:54
  • @bdonlan: Can you please explain this case: We only have one core, A: holding spin lock, B waiting for spin lock (Probably B is sleeping). Interrupt is firing. A now should be sleep. After interrupt handler is finished, which one will take the spinlock, A or B? – Hoang Pham Nov 22 '19 at 09:58
  • @HoangPham Preemption is not allowed while a spinlock is held, so after the interrupt completes execution returns to A. Note that A does _not_ go to sleep (a context switch does not occur) – bdonlan Jan 26 '20 at 16:03
  • Thanks @bdonlan. If A is running, and A and B does not hold any lock. After interrupt completes execution, It's possible to have preemption (B get the CPU) is that correct ? – Hoang Pham Jan 27 '20 at 18:48
8
  • Actually, you can sleep with interrupts disabled or some other sort of exclusion active. If you don't, the condition for which you are sleeping could change state due to an interrupt and then you would never wake up. The sleep code would normally never be entered without an elevated priority or some other critical section that encloses the execution path between the decision to sleep and the context switch.

  • But for spinlocks, sleep is a disaster, as the lock stays set. Other threads will spin when they hit it, and they won't stop spinning until you wake up from the sleep. That could be an eternity compared to the handful of spins expected in the worst case at a spinlock, because spinlocks exist just to synchronize access to memory locations, they aren't supposed to interact with the context-switching mechanism.

    (For that matter, every other thread might eventually hit the spinlock and then you would have wedged every thread of every core of the entire system.)

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • Can you elaborate on the first point? – SHH Oct 23 '11 at 18:54
  • The first point is wrong. You can't sleep with interrupts disabled; to deal with the races alluded to there, just do things in the right order: set your state to TASK_INTERRUPTIBLE, check the condition, and then `schedule()` -- or just use `wait_event()`, which handles this for you. – Roland Oct 24 '11 at 13:18
  • @Roland, I was just referring to the perspective of the kernel process code, so you _can,_ in the sense of calling a `schedule()` or `sleep()` entry point. The kernel's sleep mechanism will re-enable interrupts. All common kernels are SMP now so disabling interrupts doesn't accomplish much any more, but sure, it won't execute any hardware _wait-for-interrupt_ instructions without re-enabling interrupts. – DigitalRoss Nov 29 '16 at 00:03
1

You cannot when you use a spin lock as it is meant to be used. Spin locks are used where really necessary to protect critical regions and shared data structures. If you acquire one while also holding a semaphore, you lock access to whichever critical region (say) your lock is attached to (it is typically a member of a specific larger data structure), while allowing this process to possibly be put to sleep. If, say, an IRQ is raised while this process sleeps, and the IRQ handler needs access to the critical region still locked away, it's blocked, which can never happen with IRQs. Obviously, you could make up examples where your spin lock isn't used the way it should be (a hypothetical spin lock attached to a nop loop, say); but that's simply not a real spin lock found in Linux kernels.

gnometorule
  • 2,151
  • 2
  • 20
  • 29