This article reprinted from: http://blog.chinaunix.net/uid-9620812-id-3833377.html, if necessary, please visit.
Technorati Tags: Linux soft interrupt
---------------------------------------I'm a split line----------------------------------------
first, soft interrupt registration
Similar to hard interrupts, soft interrupts also have a similar interrupt vector table, but are implemented using "software".
struct Softirq_action softirq_vec[32] is a soft interrupt vector table
(File linux_2_6_24/kernel/softirq.c)
- struct softirq_action
- {
- void (*action) (struct softirq_action *); hook function
- void *data; The formal parameters of the hook function
- };
The interrupt vector used by the kernel (which is actually the array subscript) is shown below
(File linux_2_6_24/include/linux/interrupt.h)
- enum{
- Hi_softirq=0,//high-priority Tasklet
- TIMER_SOFTIRQ,//CORE timer
- NET_TX_SOFTIRQ,//Network send
- NET_RX_SOFTIRQ,//network receive
- BLOCK_SOFTIRQ,//???
- TASKLET_SOFTIRQ,//Common Tasklet
- Sched_softirq
- }
The kernel registers a soft interrupt function, which is essentially initializing an array of elements
- void Open_softirq (int nr, void (*action) (struct softirq_action*), void *data)
- {//NR is the soft interrupt vector number
- Softirq_vec[nr].data = data;
- Softirq_vec[nr].action = action;
- }
Where the kernel registers soft interrupts are:
- Start_kernel ()
- -->init_timers ()
- -->OPEN_SOFTIRQ (Timer_softirq,run_timer_softirq,null)
- -->softirq_init ()
- -->OPEN_SOFTIRQ (TASKLET_SOFTIRQ, Tasklet_action,null)
- -->OPEN_SOFTIRQ (Hi_softirq,tasklet_hi_action,null)
- -->do_initcall ()
- -->net_dev_init ()
- -->OPEN_SOFTIRQ (NET_TX_SOFTIRQ, net_tx_action, NULL);
- -->OPEN_SOFTIRQ (NET_RX_SOFTIRQ, net_rx_action, NULL);
- -->blk_dev_init ()
- -->OPEN_SOFTIRQ (BLOCK_SOFTIRQ, Blk_done_softirq,null)
second, soft interrupt trigger
The previous registration is over, and now it starts firing.
The kernel uses a data structure to mark that a "soft interrupt" has occurred (or that a soft interrupt has been triggered).
__softirq_pending A total of 32bit, that is, each bit corresponds to a soft interrupt vector, the actual use of 6 bit
The nth bit 1, or softirq_vec[n] has a soft interrupt to occur.
- typedef struct {
- unsigned int __softirq_pending; /* Set_bit is used on this */
- unsigned int __last_jiffy_stamp;
- } ____cacheline_aligned irq_cpustat_t;
- extern irq_cpustat_t irq_stat[]; /* defined in Asm/hardirq.h */
- #define __IRQ_STAT (CPU, member) (Irq_stat[cpu].member)
- #define LOCAL_SOFTIRQ_PENDING () \
- __irq_stat (smp_processor_id (), __softirq_pending)
- #define SET_SOFTIRQ_PENDING (x) (local_softirq_pending () = (x))
- #define OR_SOFTIRQ_PENDING (x) (Local_softirq_pending () |= (x))
- #define __raise_softirq_irqoff (NR) do {or_softirq_pending (1UL << (NR)),} while (0)
Commonly used soft interrupt trigger function
- void Raise_softirq_irqoff (int nr) {//nr = soft interrupt vector number
- __raise_softirq_irqoff (NR);
- }
But this is just a "trigger" soft interrupt, and the soft interrupt is not immediately processed
third, soft interrupt processing
function _ _do_softirq is a one-time processing of all soft interrupts (subtext, soft interrupts not nested) from high to low in the vector table
_ _do_softirq () Call timing:
1. Irq_exit () hardware interrupt is finished, call on return
- DO_IRQ ()-->irq_exit ()
- -->local_softirq_pending ()
- -->_ _DO_SOFTIRQ ()
2. KSOFTIRQD () is used to assist the kernel thread that handles soft interrupts, and a KSOFTIRQD is running on each of the CPUs.
- Start_kernel ()-Kernel_init ()-->do_pre_smp_initcalls ()
- -->SPAWN_KSOFTIRQD ()-->cpu_callback ()
- -->kthread_create (KSOFTIRQD, Hcpu, "ksoftirqd/%d", HOTCPU)
- -->KSOFTIRQD ()
- -->local_softirq_pending ()
- -->_ _DO_SOFTIRQ ()
3. Local_bh_enable (), found a soft interrupt to be processed and was not in the context of a soft and hard interrupt
- Local_bh_enable ()
- -->local_softirq_pending ()
- -->_ _DO_SOFTIRQ ()
Handling process code in a detailed
- asmlinkage void __do_softirq (void)
- {
- struct Softirq_action *h;
- __U32 pending;
- int max_restart = Max_softirq_restart;
- int CPU;
- Pending = Local_softirq_pending ();
- Account_system_vtime (current);
- /* Soft interrupt processing, disable soft interrupt re-entry, soft interrupt processing is non-reentrant */
- __local_bh_disable ((unsigned long) __builtin_return_address (0));
- Trace_softirq_enter ();
- CPU = smp_processor_id ();
- Restart
- /* Reset the pending bitmask before enabling IRQs
- The following first clears the pending so that the system can activate other software interrupts,
- Then enable external interrupts
- System in the following processing, will enable external interrupts to improve the system's response,
- Note that you must first clear the pending, and then enable the external interrupt, or the deadlock */
- Set_softirq_pending (0);
- Local_irq_enable ();
- h = Softirq_vec;
- /* Follow the handle registered with OPEN_SOFTIRQ from high to low key */
- do {
- if (pending & 1) {
- h->action (h); //Key sentence, Tasklet, kernel timer, network interrupt is here.
- Rcu_bh_qsctr_inc (CPU);
- }
- h++;
- Pending >>= 1;
- } while (pending);
- Local_irq_disable ();
- Pending = Local_softirq_pending ();
- if (pending &&--max_restart)
- Goto Restart;
- if (pending)
- WAKEUP_SOFTIRQD ();
- Trace_softirq_exit ();
- Account_system_vtime (current);
- _local_bh_enable ();
- }
Linux Soft Interrupt