2
votes

I'm a bit confused as to what constitutes an interrupt in the Linux kernel. From what I understand, spin_lock_irqsave() / spin_lock_irqrestore() ensure that my critical section won't be preempted by an interrupt handler. Fair enough.

But I'm a bit confused by what constitutes an interrupt handler. First, I'm not 100% sure that I'm also protected from preemption from softirqs. Is this the case?

What about exceptions? From what I understand, they're the same thing as interrupts, but not really. Am I protected from preemption by a page fault handler when I use spin_lock_irqsave() for instance? What precisely happens when a page fault occurs, is the mechanism used to handle them the exact same thing as interrupts?

What about signal handlers? I don't get how those are implemented. What if I send a signal a SIGTERM, SIGINT, or SIGKILL signal? Is this implemented with a soft IRQ? something else? Can such a signal preempt my critical section when I use spin_lock_irqsave()? Or not at all because those signals are handled exclusively in user space?

What about calls to schedule()? Can those preempt me at any time, even in my critical sections when I use spin_lock_irqsave()?

I guess what I'd really like to know is what exactly can preempt me when I use spin_lock_irqsave(). Nobody who uses the same lock as me, and no interrupt handlers, for sure. What about all these other things? What about softirqs/tasklets/work queues?

Finally, is spin_lock_irqsave() stronger than spin_lock_bh()? I.e., does spin_lock_irqsave() prevent preemption from bottom halves (i.e., softirqs, tasklets, and work queues)?

I've been Googling all of this quite a bit, but I find it hard to find clear answers.

1

1 Answers

4
votes

spin_lock_irqsave takes a lock and disables (temporarily masks) interrupts. You will not experience an interrupt until you release the lock (or otherwise re-enable interrupts -- which you shouldn't do). Likewise, you will not and cannot be preempted since preemption requires an interrupt in order to cause a transfer of control.

An interrupt is a signal from an external device indicating that it needs attention. The CPU hardware supports a mechanism allowing automatic transfer of control to an "interrupt handler" when the interrupt signal is asserted (but this can be temporarily masked which is what spin_lock_irqsave does).

Exceptions are similar to interrupts except they are caused by the program execution not by external hardware/devices. So this includes divide-by-zero, illegal instructions, page faults. In all but the most unusual cases, your code should ensure there are no exceptions. For example, you should not be causing a page fault when you hold a spin lock. This will result in a kernel OOPS.

Signal handlers are primarily a user-mode concept. Signals sent to a process are checked for explicitly by the kernel at times when it's appropriate to do so, and either cause an action directly (like process termination) or cause the next return to user mode in that process to vector to the user code signal handler. You should not access any code that would do that while you hold the spin lock.

Likewise, you may not call schedule while you hold a spin lock, because...

Spin locks are intended to be held for very short periods of time to protect against simultaneous access to data structures that are shared across multiple processors. The reason interrupts are disabled is so that you can assure that the task holding the spin lock doesn't get preempted -- because if it did, other CPUs could be left spinning for a long time or even forever.

... and schedule is specifically intended to allow you to give up control to another task.

See also this article. Specific details are probably outdated but all the concepts are still valid. https://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/