Linux Kernel Development - Robert Love 설지훈
Contents Interrupts and interrupt handlers Bottom halves and deferring work
Introduction Interrupts Interrupts are special electrical signals sent from hardware devices to the processor The operating system can service each interrupt with a unique handler These interrupt values are often called interrupt request (IRQ) lines Example, zero is timer, one is keyboard.
Interrupts and interrupt handlers The function the kernel runs in response to a specific interrupt is called an interrupt handler or interrupt service routine (ISR) The interrupt handler for a device is part of the devices’s driver The interrupt handler execute in as short a period as possible
Registering an interrupt handler Parameters irq Specifies the interrupt number to allocate handler A pointer to the actual interrupt handler that services this interrupt irqflags SA_INTERRUPT, SA_SAMPLE_RANDOM, SA_SHIRQ devname An ASCII text representation of the device associated with the interrupt dev_id Used primarily for shared interrupt lines Note request_irq() might sleep and, therefore, cannot be called from interrupt context or other situations where code cannot block int request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id)
Freeing an interrupt handler If the interrupt line is shared, the handler identified via dev_id is removed A call to free_irq() must be made from process context void free_irq (unsigned int irq, void *dev_id)
Writing an interrupt handler static irqreturn_t intr_handler (int irq, void *dev_id, struct pt_regs *regs) Parameter regs Holds a pointer to a structure containing the processor registers and state prior to servicing the interrupt. They are rarely used, except for debugging Return value of an interrupt handler IRQ_NONE Detects an interrupt for which its device was not the originator IRQ_HANDLED Correctly invoked, and its device did cause the interrupt
Shared handlers A shared handler is registered and executed much like a non-shared handler. Three main differences are The SA_SHIRQ flag must be set in the flags argument to request_irq() The dev_id argument must be unique to each registered handler. The interrupt handler must be capable of distinguishing whether its device actually generated an interrupt
Interrupt context When executing an interrupt handler or bottom half, the kernel is in interrupt context Interrupt context is not associated with a process Interrupt context cannot sleep Interrupt context is time critical Interrupt handler does not receive its own stack Instead, it shares the kernel stack of the process or idle task’s stack
Implementation of interrupt handling int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { int status = 1; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { status |= action->flags; action ->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return status; }
/proc/interrupts
Interrupt control Reasons to control the interrupt system generally boil down to needing to provide synchronization Kernel code more generally needs to obtain some sort of lock to prevent access to shared data simultaneously from another processor These locks are often obtained in conjunction with disabling local interrupts
Disabling and Enabling interrupts To disable interrupts locally for the current processor (and only the current processor) and later enable them: local_irq_disable(); /* interrupts are disabled */ local_irq_enabled();
Bottom Halves and Deferring Work Interrupt limitations include They need to run as quickly as possible Interrupt handlers are often very timing-critical because they deal with hardware Interrupt handlers do not run in process context, therefore, they cannot block Managing interrupts is divided two parts Interrupt handlers (top halves) Interrupt-related work not performed by the interrupt handler (bottom halves)
Bottom halves Why bottom halves? A world of bottom halves Interrupt handlers run with the current interrupt line disabled or all local interrupt disabled The bottom half runs later with all interrupts enabled Later is often simply not now A world of bottom halves BH (bottom halves) Removed in 2.5 Task queues Softirq Available since 2.3 Tasklet Work queues Available since 2.5
Softirqs Implementation of Softirqs Statically allocated at compile-time There can be a possible 32 softirqs (fixed)