LWN.net Logo

Handling interrupts in user space

Peter Chubb has long been working on a project to move device drivers into user space. Getting drivers out of the kernel, he points out, would have a number of benefits. Faults in drivers (the source of a large percentage of kernel bugs) would be less likely to destabilize the entire system. Drivers could be easily restarted and upgraded. And a user-space implementation would make it possible to provide a relatively stable driver API, which would appeal to many vendors.

Much of the support needed for user-space drivers is already in place. A process can communicate with hardware by mapping the relevant I/O memory directly into its address space, for example; that is how the X server works with video adaptors. One piece, however, is missing: user-space drivers cannot handle device interrupts. In many cases, a proper driver cannot be written without using interrupts, so a user-space implementation is not possible.

Peter has now posted his user-space interrupts patch for review and possible inclusion. The mechanism that he ended up with is simple and easy to work with, but it suffers from an important limitation.

The mechanism is this: a process wishing to respond to interrupts opens a new /proc file; for IRQ 10, the file would be /proc/irq/10/irq. A read on that file will yield the number of interrupts which have occurred since the last read. If no interrupts have occurred, the read() call will block until the next interrupt happens. The select() and poll() system calls are properly supported, so it is possible to include interrupt handling as just another thing to do in an event loop.

On the kernel side, the real interrupt handler looks like this:

    static irqreturn_t irq_proc_irq_handler(int irq, void *vidp, 
                                            struct pt_regs *regs)
    {
 	struct irq_proc *idp = (struct irq_proc *)vidp;
 
 	BUG_ON(idp->irq != irq);
 	disable_irq_nosync(irq);
 	atomic_inc(&idp->count);
 	wake_up(&idp->q);
 	return IRQ_HANDLED;
    }

In other words, all it does is count the interrupt and wake up any process that might be waiting to handle it.

The handler also disables the interrupt before returning. There is an important reason for this action: since the handler knows nothing of the device which is actually interrupting, it is unable to acknowledge or turn off the interrupt. So, when the handler returns, the device will still be signalling an interrupt. If the interrupt were not disabled in the processor (or the APIC), the processor would be interrupted (and the handler called) all over again, repeatedly - at least, when level-triggered interrupts are in use. Disabling the interrupt allows life to go on until the user-space process gets scheduled and is able to tend to the interrupting device.

There is a problem here, however: interrupt lines are often shared between devices. Disabling a shared interrupt shuts it off for all devices using that line, not just the one being handled by a user-space driver. It is entirely possible that masking that interrupt will block a device which is needed by the user-space handler - a disk controller, perhaps. In that case, the system may well deadlock. For this reason, the patch does not allow user-space drivers to work with shared interrupts. This restriction avoids problems, but it also reduces the utility of the whole thing.

One possible solution was posted by Alan Cox. He would require user-space processes to pass a small structure into the kernel describing the hardware's IRQ interface. It would be just enough for the kernel to tell if a particular device is interrupting, acknowledge that interrupt, and tell the device to shut up. With that in place, the kernel could let user space deal with what the device really needs while leaving the interrupt enabled. It has been pointed out that this simple scheme would not work with some of the more complicated hardware, but it would be a step in the right direction regardless.

Meanwhile, Michael Raymond described a different user-space interrupt implementation (called "User Level Interrupt" or ULI) done at SGI. This patch is significantly more complicated. In this scheme, a user-space driver would register an interrupt handler function directly with the kernel. When an interrupt happens, the ULI code performs some assembly-code black magic so that its "return from interrupt" instruction jumps directly into the user-space handler, in user mode. Once that handler returns, the ULI library writes a code to a magic device which causes the kernel stack and related data structures to be restored to their pre-interrupt state. The implementation is more complex, and it currently only works on the ia-64 architecture, but it could conceivably offer better performance than the /proc method.


(Log in to post comments)

Does it really stabilise the system?

Posted Mar 17, 2005 12:20 UTC (Thu) by NAR (subscriber, #1313) [Link]

Faults in drivers [...] would be less likely to destabilize the entire system. [...] A process can communicate with hardware by mapping the relevant I/O memory directly into its address space, for example; that is how the X server works with video adaptors.

Would the user space driver make the system really that more stable? I mean the X server can easily lock up my system even from user mode...

Bye,NAR

Does it really stabilise the system?

Posted Mar 17, 2005 13:47 UTC (Thu) by nix (subscriber, #2304) [Link]

Ideally, the X server would not need to use iopl() or run suid root: this is a step in that direction. In that situation, the most it could do without a kernel bug is lock up the console (maybe not even that).

Does it really stabilise the system?

Posted Mar 17, 2005 15:20 UTC (Thu) by gnb (subscriber, #5132) [Link]

> In that situation, the most it could do without a kernel bug is lock up
>the console (maybe not even that).
That's optimistic. Any driver for a DMA-capable device can pretty much
obliterate the system. Moving stuff into user-space should eliminate
some classes of crash, but it's not the answer to everything.

Does it really stabilise the system?

Posted Mar 18, 2005 23:06 UTC (Fri) by giraffedata (subscriber, #1954) [Link]

Moving stuff into user-space should eliminate some classes of crash, but it's not the answer to everything.

Indeed. But the point of this proposal is that it eliminates not only some classes of crash, but the vast majority of the crashes. If it were only a few classes, it wouldn't be worth it.

A few examples of common coding errors that would obliterate the system in a real interrupt handler, but have relatively minor impact in a user interrupt handler process: infinite loop, wild pointer to nonexistent address, store into an arbitrary address.

The SGI ULI thing, though, is a horse of a different color. This eliminates relatively few risks and adds others.

Handling interrupts in user space

Posted Mar 17, 2005 22:18 UTC (Thu) by rgoates (guest, #3280) [Link]

Peter Chubb's solution for user-space interrupts seems to turn the asynchronous nature of interrupts into polling, which is certainly not asynchronous and is something I learned to dislike as a real-time programmer. This might work for some drivers but it doesn't sound like a good general solution. SGI's ULI at least retains the asynchronicity of interrupts.

Handling interrupts in user space

Posted Mar 17, 2005 22:40 UTC (Thu) by obobo (guest, #684) [Link]

Well, if you make a task that is just sitting (via poll or select) on that event, it will act pretty much exactly like an interrupt handler for that event. If you decide to use a single thread/task and just poll it periodically, of course, it won't.

Handling interrupts in user space

Posted Mar 25, 2005 6:00 UTC (Fri) by goaty (guest, #17783) [Link]

It seems to me that if we're going to require the kernel to have some knowledge of how to handle interrupts, we may as well make it pluggable.

In other words, when our userspace driver starts up, it loads two modules, one which contains the infrastructure for userspace module delivery, and another which contains the logic necessary to confirm receipt of an interrupt.

Drivers that only handle simple edge-trigger interrupts could simply load the module for that case (which would be effectively a null implementation) and not need any further configuration.

Drivers that needed more fully-fledged interrupt handling could upload a module that supported the interface Alan Cox suggested. Perhaps it could be programmed by module parameters? IIRC, the infrastructure to make that trivial is already in place.

Drivers with really complex interrupt requirements would obviously need their own module, but it would still be simpler than writing the whole driver in kernelspace. The benefit is that this complexity can be supported without complicating things for other users of the interface.

I think this idea has enormous potential. Drivers could be prototyped in Perl or your favourite rapid-turnaround language. You could even do it interactively.

Copyright © 2005, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds