Moving interrupts to threads
Processing interrupts from the hardware is a major source of latency in the kernel, because other interrupts are blocked while doing that processing. For this reason, the realtime tree has a feature, called threaded interrupt handlers, that seeks to reduce the time spent with interrupts disabled to a bare minimum—pushing the rest of the processing out into kernel threads. But it is not just realtime kernels that are interested in lower latencies, so threaded handlers are being proposed for addition to the mainline.
Reducing latency in the kernel is one of the benefits, but there are other advantages as well. The biggest is probably reducing complexity by simplifying or avoiding locking between the "hard" and "soft" parts of interrupt handling. Threaded handlers will also help the debuggability of the kernel and may eventually lead to the removal of tasklets from Linux. For these reasons, and a few others as well, Thomas Gleixner has posted a set of patches and a "request for comments" to add threaded interrupt handlers.
Traditionally, interrupt handling has been done with top half (i.e. the "hard" irq) that actually responds to the hardware interrupt and a bottom half (or "soft" irq) that is scheduled by the top half to do additional processing. The top half executes with interrupts disabled, so it is imperative that it do as little as possible to keep the system responsive. Threaded interrupt handlers reduce that work even further, so the top half would consist of a "quick check handler" that just ensures the interrupt is from the device; if so, it simply acknowledges the interrupt to the hardware and tells the kernel to wake the interrupt handler thread.
In the realtime tree, nearly all drivers were mass converted to use
threads, but the patch Gleixner proposes makes it optional—driver
maintainers can switch if they wish to. Automatically converting drivers
is not necessarily popular with all maintainers, but it has an additional
downside as Gleixner notes: "Converting an interrupt to threaded
makes only sense when the handler
code takes advantage of it by integrating tasklet/softirq
functionality and simplifying the locking
".
A driver that wishes to request a threaded interrupt handler will use:
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t quick_check_handler, unsigned long flags, const char *name, void *dev)This is essentially the same as request_irq() with the addition of the quick_check_handler. As requested by Linus Torvalds at this year's Kernel Summit, a new function was introduced rather than changing countless drivers to use a new request_irq().
The quick_check_handler checks to see if the interrupt was from the device, returning IRQ_NONE if it isn't. It can also return IRQ_HANDLED if no further processing is required or IRQ_WAKE_THREAD to wake the handler thread. One other return code was added to simplify converting to a threaded handler. A quick_check_handler can be developed prior to the handler being converted; in that case, it returns IRQ_NEEDS_HANDLING (instead of IRQ_WAKE_THREAD) which will call the handler in the usual way.
request_threaded_irq() will create a thread for the interrupt and put a pointer to it in the struct irqaction. In addition, a pointer to the struct irqaction has been added to the task_struct so that handlers can check the action flags for newly arrived interrupts. That reference is also used to prevent thread crashes from causing an oops. One of the few complaints seen so far about the proposal was a concern about wasting four or eight bytes in each task_struct that was not an interrupt handler (i.e. the vast majority). That structure could be split into two types, one for the kernel and one for user space, but it is unclear whether that will be necessary.
Andi Kleen has a more general concern that threaded interrupt handlers will
lead to bad code:
"to be
honest my opinion is that it will encourage badly written interrupt
code longer term
", but he seems to be in the minority. There were
relatively few comments, but most seemed in favor—perhaps many are
waiting to see the converted driver as Gleixner promises to deliver "real
soon". If
major obstacles don't materialize, one would guess the linux-next tree
would be a logical next step, possibly followed by mainline merging for 2.6.29.
Index entries for this article | |
---|---|
Kernel | Interrupts |
Posted Oct 9, 2008 1:32 UTC (Thu)
by bronson (subscriber, #4806)
[Link]
This sounds like a neat idea and well worth the potential code churn. I look forward to hearing more news as this develops.
Posted Oct 9, 2008 15:48 UTC (Thu)
by jengelh (subscriber, #33263)
[Link]
Posted Oct 9, 2008 21:46 UTC (Thu)
by magnus (subscriber, #34778)
[Link] (8 responses)
The only reason I can come up with is that it is an API issue, i e interrupts are re-enabled when the handler returns and the call to schedule the bottom half has to be done inside the handler..
Posted Oct 10, 2008 4:53 UTC (Fri)
by jzbiciak (guest, #5246)
[Link]
Posted Oct 10, 2008 12:10 UTC (Fri)
by jzbiciak (guest, #5246)
[Link] (3 responses)
Other than my terse reply (which only answers "why can't I reenable interrupts in my top half?"), I must say, after re-reading the article, I too am not clear on what the difference is here. The current top half looks similar in principle to the quick_check_handler and the current bottom half looks like the handler thread.
Is it just that even more work is pushed out of the top half into the bottom half via action flags in struct irqaction? I guess I don't know enough kernel internals to appreciate the significance of this change, or why the current top half/bottom half structure couldn't do the same. Is this just a cheap event queuing construct that gets around the "can't sleep" aspect of interrupt handler top halves?
Posted Oct 10, 2008 12:55 UTC (Fri)
by jlokier (guest, #52227)
[Link] (2 responses)
So if you have some device which is dominating the machine, like say a network device flooded with tiny packets at line rate, in the old scheme userspace would effectively lock up, and in the new scheme, the network device's handlers will get their fair share of the CPU according to the scheduler.
(This is not a great example because many of the popular network drivers have another mechanism to limit their effect already. But the new scheme is more controlled.)
It also means you can manage the priority of interrupts using thread priorities (RT and non-RT, and "nice"), task control groups, and other things used to manage threads, and they can be dispatched to under-utilised CPUs more efficiently, and interact with thermal and power management.
The need to have quick_check_handler separate from the main handler seems to be due to shared interrupt lines. Without quick_check_handler, multiple devices on the same line would need to share the same handler thread, and interfere with each other.
It's possible to abuse quick_check_handler and write code in the same form as the old top/bottom halves. There are probably some latency-sensitive devices where it's essential to do something more than just acknowledging and disabling the device interrupt. However, that's not the intended way of using it, and if a device is latency sensitive, it should probably use a high RT priority on its handler thread instead. If the thread scheduler is too slow at this, it may be possible to tune this particular path through the scheduler, taking a short cut from irq to task, but retaining the standard scheduling semantics.
Posted Oct 10, 2008 13:21 UTC (Fri)
by jzbiciak (guest, #5246)
[Link] (1 responses)
Did I understand you correctly?
Posted Oct 10, 2008 14:05 UTC (Fri)
by jlokier (guest, #52227)
[Link]
Also threaded interrupts can sleep, take locks and allocate memory as normal threads.
Posted Oct 10, 2008 14:53 UTC (Fri)
by jake (editor, #205)
[Link] (2 responses)
Sorry I wasn't more clear in the article. Without threaded interrupts, there is no mechanism for the rest of the work to get done without being explicitly arranged for by the top half (i.e. tasklets or workqueues). This necessitates locking and synchronization between the two pieces. Workqueues have a fair amount of overhead and tasklets must still run atomically (i.e. no sleeping, etc.) as well.
Threaded interrupts provide the mechanism for additional work to be done outside of the top half, more or less automatically.
Hopefully I didn't botch this explanation as well :)
jake
Posted Oct 16, 2008 14:42 UTC (Thu)
by neli (guest, #51380)
[Link] (1 responses)
Posted Apr 10, 2011 15:01 UTC (Sun)
by abacus (guest, #49001)
[Link]
Posted Oct 11, 2008 16:34 UTC (Sat)
by MisterIO (guest, #36192)
[Link]
Posted Oct 22, 2008 22:27 UTC (Wed)
by HalfMoon (guest, #3211)
[Link]
This will be handy for interrupts issued from I2C and SPI chips, too ... their handlers mostly need to run in task context, since they've got to block while their messages get to the head of the I/O queue and also while waiting for the response. Example: IRQ comes in, block until the IRQ status mask comes back from the chip. (Even when that serial bus was idle when the IRQ came in, the handler must block.)
It's not clear how useful it will be for chained handlers though. As in, an I2C chip may have a few dozen internal IRQ sources, each of which needs to be dispatched as an IRQ in its own right. Not only will the top level dispatcher need to be a thread (possibly shared by the handlers for those internal sources) ... but all the irq_chip methods to update IRQ masks and trigger modes for those internal IRQ sources will need to run in threads, too...
Posted Dec 12, 2008 0:21 UTC (Fri)
by shishir (subscriber, #20844)
[Link]
I somehow am confused about this line. Isn't this true only for the interrupts registered with IRQF_DISABLED/SA_INTERRUPT? Any interrupt registered using IRQF_SHARED/SA_SHIRQ can be interrupted by other interrupts.
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
Moving interrupts to threads
> reduce the time needed to be spent with interrupts disabled? Couldn't a
> traditional interrupt handler also immediately just ack the interrupt and
> re-enable interrupts?
Moving interrupts to threads
Don't these threaded interrupt handlers have even more overhead than workqueues? Workqueues are at least handled sequentially in the same thread; using threaded interrupt handlers means there are even more context switches.
Why threaded interrupt handlers are important
I'm afraid that you have missed a key point about real-time systems. Design of a hard real-time system starts with deciding which threads in the system will run at real-time priority (SCHED_FIFO or SCHED_RR) and also at which priority (1..99). This step involves all threads in the system, including threaded interrupt handlers. By assigning a higher priority to certain application threads than the threaded interrupt handlers it becomes possible to obtain a system with low and bounded event response time. Handling some of the interrupt work via workqueues instead of threaded interrupt handlers would result in a larger event response time.
Moving interrupts to threads
really bad argument. If you consider "this code" to be good and useful,
then you should merge it. If then someone tries to merge "bad code" which
uses some of the features of the "good code", just don't merge the "bad
code".
Moving interrupts to threads
Moving interrupts to threads