Question

I am new to Linux and am reading Linux device drivers book by Rubini & Corbet. I am confused at one statement related to spinlocks; the book states

If a nonpreemptive uniprocessor system ever went into a spin on a lock, it would spin forever; no other thread would ever be able to obtain the CPU to release the lock. For this reason, spinlock operations on uniprocessor systems without preemption enabled are optimized to do nothing, with the exception of the ones that change the IRQ masking status.

Further the book states

The kernel preemption case is handled by the spinlock code itself. Any time kernel code holds a spinlock, preemption is disabled on the relevant processor. Even uniprocessor systems must disable preemption in this way to avoid race conditions.

Question : On a uniprocessor system, if kernel preemption is disabled whenever a kernel code (executing on behalf of the user process) holds the spinlock, then how could another process ever get a chance to run and hence try at acquring the spinlock ? Why does Linux Kernel disables kernel preemption whenever kernel code holds a spinlock?

Was it helpful?

Solution

The answer to your first question is the reasoning behind your second.

Spinlocks acquired by the kernel may be implemented by turning off preemption, because this ensures that the kernel will complete its critical section without another process interfering. The entire point is that another process will not be able to run until the kernel releases the lock.

There is no reason that it has to be implemented this way; it is just a simple way to implement it and prevents any process from spinning on the lock that the kernel holds. But this trick only works for the case in which the kernel has acquired the lock: user processes can not turn off preemption, and if the kernel is spinning (i.e. it tries to acquire a spinlock but another process already holds it) it better leave preemption on! Otherwise the system will hang since the kernel is waiting for a lock that will not be released because the process holding it can not release it.

The kernel acquiring a spinlock is a special case. If a user level program acquires a spinlock, preemption will not be disabled.

OTHER TIPS

process A and process B both access same data, so you define a SPIN LOCK. if A is holding the lock but keep preemption enabled. then A may be scheduled out, and B has a chance to run. if B try to get the lock. B will spin and waste cpu.

spin lock is designed for efficiency and protect small & fast critical zone. so spin block disable preemption. if you want lock but keep preemption enabled. you can use mutex lock.

when Process A release the lock, preemption is enabled again. so other process has a chance to run. before that, only hardware interrupt and software irqs can run.

Spinlocks disable preemption only on uniprocessors. So in case of a single processor: let's say the scheduler has the following processes in it's queue: P1, P2, P3, P4 - all requesting a spinlock L. All of them will get the lock as they are queued (i.e P1 followed by P2 etc)

The reason that preemption is disabled on a uniprocessor system is: If not: P1 holds the lock and after a time is scheduled out. Now P2 starts executing and let's say requests the same spinlock. Since P1 has not released the spinlock, P2 must spin and do nothing. So the execution time of P2 is wasted. It makes more sense to let P1 release the lock and then allow it to be preempted. Also since there is no other processor, simply by disallowing preemption we know that there will never be another process that runs in parallel on another processor and accesses the same critical section.

Similarly, if your critical section is shared with that of an interrupt, we need to disable interrupts locally on that processor. In the case of interrupts, they are never scheduled out. Thus it is important that the interrupt never requests a lock already held by the process it interrupted. Such a process will never run on any other processor as it was not scheduled out and hence it will never get a chance of releasing the lock. Thus the interrupt handler will never complete leading to a deadlock. Hence in such a case we always disable local interrupts on the processor.

Any time kernel code holds a spinlock, preemption is disabled on the relevant processor only. This means if this is a SMP system, preemption is disabled only on the current processor, other processors running concurrently still free to acquire that lock and do busy waiting. Thus a sleep after holding the spinlock can cause deadlock.

Whereas in the case of a single processor system, preemption has to be disabled because in case another process holds the lock it will keep busy waiting and won't allow the first process to release the lock.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top