Bandicoot
Bandicoot

Reputation: 3949

Why can't you sleep while holding spinlock?

In the linux kernel, why can't you sleep while holding a spinlock?

Upvotes: 16

Views: 19617

Answers (8)

Nan Wang
Nan Wang

Reputation: 776

The key point is in Linux kernel, acquiring a spin lock will disable preemption. Thus sleeping while holding a spin lock could potentially cause deadlock.

For example, thread A acquires a spin lock. Thread A will not be preempted until it releases the lock. As long as thread A quickly does its job and releases the lock, there is no problem. But if thread A sleeps while holding the lock, thread B could be scheduled to run since the sleep function will invoke the scheduler. And thread B could acquire the same lock as well. Thread B also disables preemption and tries to acquire the lock. And a deadlock occurs. Thread B will never get the lock since thread A holds it, and thread A will never get to run since thread B disables preemption.

And why disabling preemption in the first place? I guess it's because we don't want threads on other processors to wait too long.

Upvotes: 3

Nan Xiao
Nan Xiao

Reputation: 17477

I think this mail has a clarity answer:

A process cannot be preempted nor sleep while holding a spinlock due spinlocks behavior. If a process grabs a spinlock and goes to sleep before releasing it. A second process (or an interrupt handler) that to grab the spinlock will busy wait. On an uniprocessor machine the second process will lock the CPU not allowing the first process to wake up and release the spinlock so the second process can continue, it is basically a deadlock.

Upvotes: 5

steve
steve

Reputation: 41

total agree with Nan Wang. I guess most important concept is "preemption" & "scheduling" and how happen when spinlock is acquired. when spinlock is acquired, preemption is disabled(true or not, I don't know, but assume it is correct), it means timer interrupt can't preempt current spinlock holder, but current spinlock hold still call sleepable kernel functions & actively invoke scheduler & run "another task". if "another task" happened to want to acquire the same spinlock as the first spinlock holder, here is problem come: since preemption is already disabled by first spinlock holder, "another task" which is invoked by actively call of scheduler by first spinlock holder, can't be preempted out, so its spinning always take the cpu, this is why deadlock happen.

Upvotes: 0

Qylin
Qylin

Reputation: 1591

I disagree with William's response (his example). He's mixing two different concepts: preemption and synchronization.

An Interrupt Context could preempt a Process Context and thus if there a RESOURCE shared by the both, we need to use

spin_lock_irqsave()

to (1) disable the IRQ (2) acquire the lock. By step 1, we could disable interrupt preemption.

I think this thread is much convincing. Sleep() means a thread/process yields the control of the CPU and CONTEXT SWITCH to another, without releasing the spinlock, that's why it's wrong.

Upvotes: 5

San
San

Reputation: 71

Apart from what willtate has mentioned, assume that a process sleeps while holding a spilock. If the new process that is scheduled tries to acquire the same spinlock, it starts spinning for the lock to be available. Since the new process keeps spinning, it is not possible to schedule the first process and thus the lock is never released making the second process to spin for ever and we have a deadlock.

Upvotes: 2

Omair
Omair

Reputation: 874

It's not that you can't sleep while holding a spin lock. It is a very very bad idea to do that. Quoting LDD:

Therefore, the core rule that applies to spinlocks is that any code must, while holding a spinlock, be atomic. It cannot sleep; in fact, it cannot relinquish the processor for any reason except to service interrupts (and sometimes not even then).

Any deadlock like mentioned above may result in an unrecoverable state. Another thing that could happen is that the spinlock gets locked on one CPU, and then when the thread sleeps, it wakes up on the other CPU, resulting in a kernel panic.

Answering Bandicoot's comment, in a spin lock context, pre-emption is disabled only in case of a uniprocessor pre-emptible kernel because disabling pre-emption effectively prevents races.

If the kernel is compiled without CONFIG_SMP, but CONFIG_PREEMPT is set, then spinlocks simply disable preemption, which is sufficient to prevent any races. For most purposes, we can think of preemption as equivalent to SMP, and not worry about it separately.

http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html

Upvotes: 11

TheLoneJoker
TheLoneJoker

Reputation: 1629

Another likely explanation is that, in a spinlock context pre-emption is disabled.

Upvotes: 2

Will Tate
Will Tate

Reputation: 33509

Example: your driver is executing and has just taken out a lock that controls access to its device. While the lock is held, the device issues an interrupt, which causes your interrupt handler to run. The interrupt handler, before accessing the device, must also obtain the lock. Taking out a spinlock in an interrupt handler is a legitimate thing to do; that is one of the reasons that spinlock operations do not sleep. But what happens if the interrupt routine executes in the same processor as the code that took out the lock originally? While the interrupt handler is spinning, the noninterrupt code will not be able to run to release the lock. That processor will spin forever.

Source: http://www.makelinux.net/ldd3/chp-5-sect-5.shtml

Upvotes: 22

Related Questions