as far as I know, Linux has 'fast interrupts', those that were requested with SA_INTERRUPT flag; fast interrupts are executed with all other interrupts disabled on the current CPU. But how does it differ from the normal interrupt handler behavior (where)?
Linux – ‘fast interrupts’ in Linux
interruptkernellinux
Related Solutions
A hardware interrupt is not really part of CPU multitasking, but may drive it.
Hardware interrupts are issued by hardware devices like disk, network cards, keyboards, clocks, etc. Each device or set of devices will have its own IRQ (Interrupt ReQuest) line. Based on the IRQ the CPU will dispatch the request to the appropriate hardware driver. (Hardware drivers are usually subroutines within the kernel rather than a separate process.)
The driver which handles the interrupt is run on the CPU. The CPU is interrupted from what it was doing to handle the interrupt, so nothing additional is required to get the CPU's attention. In multiprocessor systems, an interrupt will usually only interrupt one of the CPUs. (As a special cases mainframes have hardware channels which can deal with multiple interrupts without support from the main CPU.)
The hardware interrupt interrupts the CPU directly. This will cause the relevant code in the kernel process to be triggered. For processes that take some time to process, the interrupt code may allow itself to be interrupted by other hardware interrupts.
In the case of timer interrupt, the kernel scheduler code may suspend the process that was running and allow another process to run. It is the presence of the scheduler code which enables multitasking.
Software interrupts are processed much like hardware interrupts. However, they can only be generated by processes which are currently running.
Typically software interrupts are requests for I/O (Input or Output). These will call kernel routines which will schedule the I/O to occur. For some devices the I/O will be done immediately, but disk I/O is usually queued and done at a later time. Depending on the I/O being done, the process may be suspended until the I/O completes, causing the kernel scheduler to select another process to run. I/O may occur between processes and the processing is usually scheduled in the same manner as disk I/O.
The software interrupt only talks to the kernel. It is the responsibility of the kernel to schedule any other processes which need to run. This could be another process at the end of a pipe. Some kernels permit some parts of a device driver to exist in user space, and the kernel will schedule this process to run when needed.
It is correct that a software interrupt doesn't directly interrupt the CPU. Only code that is currently running code can generate a software interrupt. The interrupt is a request for the kernel to do something (usually I/O) for running process. A special software interrupt is a Yield call, which requests the kernel scheduler to check to see if some other process can run.
Response to comment:
For I/O requests, the kernel delegates the work to the appropriate kernel driver. The routine may queue the I/O for later processing (common for disk I/O), or execute it immediately if possible. The queue is handled by the driver, often when responding to hardware interrupts. When one I/O completes, the next item in the queue is sent to the device.
Yes, software interrupts avoid the hardware signalling step. The process generating the software request must be a currently running process, so they don't interrupt the CPU. However, they do interrupt the flow of the calling code.
If hardware needs to get the CPU to do something, it causes the CPU to interrupt its attention to the code it is running. The CPU will push its current state on a stack so that it can later return to what it was doing. The interrupt could stop: a running program; the kernel code handling another interrupt; or the idle process.
This is covered in chapter 10 of Linux Device Drivers, 3rd edition, by Corbet et al. It is available for free online, or you may toss some shekels O'Reilly's way for dead tree or ebook forms. The part relevant to your question begins on page 278 in the first link.
For what it's worth, here is my attempt to paraphrase those three pages, plus other bits I've Googled up:
When you register a shared IRQ handler, the kernel checks that either:
a. no other handler exists for that interrupt, or
b. all of those previously registered also requested interrupt sharing
If either case applies, it then checks that your
dev_id
parameter is unique, so that the kernel can differentiate the multiple handlers, e.g. during handler removal.When a PCI¹ hardware device raises the IRQ line, the kernel's low-level interrupt handler is called, and it in turn calls all of the registered interrupt handlers, passing each back the
dev_id
you used to register the handler viarequest_irq()
.The
dev_id
value needs to be machine-unique. The common way to do that is to pass a pointer to the per-devicestruct
your driver uses to manage that device. Since this pointer must be within your driver's memory space for it to be useful to the driver, it is ipso facto unique to that driver.²If there are multiple drivers registered for a given interrupt, they will all be called when any of the devices raises that shared interrupt line. If it wasn't your driver's device that did this, your driver's interrupt handler will be passed a
dev_id
value that doesn't belong to it. Your driver's interrupt handler must immediately return when this happens.Another case is that your driver is managing multiple devices. The driver's interrupt handler will get one of the
dev_id
values known to the driver. Your code is supposed to poll each device to find out which one raised the interrupt.The example Corbet et al. give is that of a PC parallel port. When it asserts the interrupt line, it also sets the top bit in its first device register. (That is,
inb(0x378) & 0x80 == true
, assuming standard I/O port numbering.) When your handler detects this, it is supposed to do its work, then clear the IRQ by writing the value read from the I/O port back to the port with the top bit cleared.I don't see any reason that particular mechanism is special. A different hardware device could choose a different mechanism. The only important thing is that for a device to allow shared interrupts, it has to have some way for the driver to read the interrupt status of the device, and some way to clear the interrupt. You'll have to read your device's datasheet or programming manual to find out what mechanism your particular device uses.
When your interrupt handler tells the kernel it handled the interrupt, that doesn't stop the kernel from continuing to call any other handlers registered for that same interrupt. This is unavoidable if you are to share an interrupt line when using level-triggered interrupts.
Imagine two devices assert the same interrupt line at the same time. (Or at least, so close in time that the kernel doesn't have time to call an interrupt handler to clear the line and thereby see the second assertion as separate.) The kernel must call all handlers for that interrupt line, to give each a chance to query its associated hardware to see if it needs attention. It is quite possible for two different drivers to successfully handle an interrupt within the same pass through the handler list for a given interrupt.
Because of this, it is imperative that your driver tell the device it is managing to clear its interrupt assertion sometime before the interrupt handler returns. It's not clear to me what happens otherwise. The continuously-asserted interrupt line will either result in the kernel continuously calling the shared interrupt handlers, or it will mask the kernel's ability to see new interrupts so the handlers are never called. Either way, disaster.
Footnotes:
I specified PCI above because all of the above assumes level-triggered interrupts, as used in the original PCI spec. ISA used edge-triggered interrupts, which made sharing tricky at best, and possible even then only when supported by the hardware. PCIe uses message-signalled interrupts; the interrupt message contains a unique value the kernel can use to avoid the round-robin guessing game required with PCI interrupt sharing. PCIe may eliminate the very need for interrupt sharing. (I don't know if it actually does, just that it has the potential to.)
Linux kernel drivers all share the same memory space, but an unrelated driver isn't supposed to be mucking around in another's memory space. Unless you pass that pointer around, you can be pretty sure another driver isn't going to come up with that same value accidentally on its own.
Best Answer
As of today, you can mostly forget about the
SA_INTERRUPT
flag.In between 2.6.18 and 2.6.24 it was just a migration helper for the new
IRQF_DISABLED
flag.2.6.24 removed all
SA_*
flags and replaced them withIRQF_*
flags.2.6.35 marked this "new" flag as deprecated.
If you have a kernel before 2.6.18, you'll probably won't use it (see Justin's answer).
Today's usage of
IRQF_DISABLE
differs among the architectures. x86 still only uses it for time critical functions (time.c
,hpet.c
) and somexen
stuff.Concerning the difference; a normal interrupt can be interrupted by an other interrupt (preemption), a "fast" one on the other hand, can not.