4

I read that on a system with 1 CPU and non preemtive linux kernel (2.6.x) a spin_lock call is equivalent to an empty call, and thus implemented that way.

I can't understand that: shouldn't it be equivalent to a sleep on a mutex? Even on non-preemtive kernels interrupt handlers may still be executed for example or I might call a function that would put the original thread to sleep. So it's not true that an empty spin_lock call is "safe" as it would be if it was implemented as a mutex.

Is there something I don't get?

Emiliano
  • 22,232
  • 11
  • 45
  • 59

4 Answers4

6

If you were to use spin_lock() on a non-preemptive kernel to shield data against an interrupt handler, you'd deadlock (on a single-processor machine).

If the interrupt handler runs while other kernel code holds the lock, it will spin forever, as there is no way for the regular kernel code to resume and release the lock.

Spinlocks can only be used if the lock holder can always run to completion.

The solution for a lock that might be wanted by an interrupt handler is to use spin_lock_irqsave(), which disables interrupts while the spinlock is held. With 1 cpu, no interrupt handler can run, so there will not be a deadlock. On smp, an interrupt handler might start spinning on another cpu, but since the cpu holding the lock can't be interrupted, the lock will eventually be released.

Eric Seppanen
  • 5,923
  • 30
  • 24
6

To answer the two parts of your question:

Even on non-preemtive kernels interrupt handlers may still be executed for example ...

spin_lock() isn't supposed to protect against interrupt handlers - only user context kernel code. spin_lock_irqsave() is the interrupt-disabling version, and this isn't a no-op on a non-preemptive uniprocessor.

...or I might call a function that would put the original thread to sleep.

It is not allowed to sleep while holding a spin lock. This is the "Scheduling while atomic" bug. If you want to sleep, you have to use a mutex instead (again - these aren't a no-op on non-preemptive uniprocessor).

caf
  • 233,326
  • 40
  • 323
  • 462
5

Quoted from «Linux Device Drivers», by Jonathan Corbet, Alessandro Rubini and Greg Kroah-Hartman:

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 (because it couldn't yield). Because of this, 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 (in Linux, that would be spin_lock_irqsave()). Because of preemption, even if you never expect your code to run on an SMP system, you still need to implement proper locking.

If you're interested in a spinlock that can be taken by code running in interrupt context (hardware or software), you must use a form of spin_lock_* that disables interrupts. Not doing so will deadlock the system as soon as an interrupt arrives while you have entered your critical section.

Macmade
  • 52,708
  • 13
  • 106
  • 123
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
  • Actually the situation is the same for pre-emptive uniprocessor systems as the spin_lock call disables pre-emption. – Dipstick Jul 02 '11 at 08:11
  • -1 for copy/paste without attribution. When quoting, please make it clear and at least provide the original author name! http://books.google.ch/books?id=M7RHMACEkg4C&pg=PT137&lpg=PT137&dq=%22If+a+nonpreemptive+uniprocessor+system+ever+went+into+a+spin+on+a+lock%22&source=bl&ots=s1I5OjeNVv&sig=VklYdozQ9pAkuzxUAdvlPjcFHe8&hl=en&sa=X&ei=s_7tUJ_UJ6qN4gS68oHACg&ved=0CFoQ6AEwBw – Macmade Jan 09 '13 at 23:38
1

By definition, if you're using a non-preemptive kernel, you won't be preempted. If you do your own multitasking, that's not the kernel's problem; that's your problem. Interrupt handlers may still be executed, but they won't cause context switches.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
  • 1
    Also, does that mean that I can't make possibly-blocking calls in my spinlock critical sections? (like kmalloc or printk?) – Emiliano Jul 30 '10 at 14:56
  • Spinlocks shouldn't be used by IRQs unless all other users of the spinlock disable IRQs (see Erics answer) before grabbing the lock. The situation you describe would lead to deadlock if it were allowed (the processor is spinning in the IRQ handler, but the lock can never be released without the processor running the other piece of code). – Thomas M. DuBuisson Jul 30 '10 at 18:59
  • @happy_emi To answer your other question, while holding a spinlock you should not make calls that may block, sleep, or reschedule, as that could also lead to deadlock. – Eric Seppanen Jul 30 '10 at 21:54