Implementation of Linux kernel soft interrupt and its derivative-timer Tasklet

Source: Internet
Author: User

The concept of soft interrupts can have two different interpretations in embedded development:
First, soft interrupts in the processor design is one of the processor exceptions, the program software uses the specified instruction (such as ARM's SWI instruction) to throw the exception into the kernel state execution, the most typical software application is the system call.
Secondly, a set of soft interrupt mechanism is implemented in kernel code, which is different from hardware interrupt hardware triggering software processing, but software triggering software processing.

What we are learning today is the soft interrupt mechanism under kernel,

Learning the most commonly used hardware interrupts, we are most concerned about interrupt triggering (hardware)-Interrupt distribution-how this process is done, and we need to figure out what to do with soft interrupts.

First, we look at the structure variables associated with soft interrupts in kernel, in kernel/softirq.c, as follows:

static The struct softirq_action Softirq_vec[nr_softirqs] __cacheline_aligned_in_smp;softirq_vec array represents the soft interrupts for all registrations under kernel. struct softirq_action{void (*action) (struct softirq_action *);}; The array subscript represents the soft interrupt number, and the softirq_action represents the soft interrupt handler function. The Softirq_vec is similar to irq_desc that characterize hardware interrupts under kernel. /* Please, avoid to allocate new SOFTIRQS, if you need not _really_ high frequency threaded job scheduling. For almost all the purposes tasklets is more than enough. F.E. All serial device BHs et al should is converted to tasklets, not to Softirqs. */enum{hi_softirq=0, Timer_softirq, Net_tx_softirq, Net_rx_softirq, BLOCK_SOFTIRQ, BLOCK_IOPOLL_SOFTIRQ  , Tasklet_softirq, Sched_softirq, HRTIMER_SOFTIRQ, RCU_SOFTIRQ,/* Preferable RCU should always being the last SOFTIRQ */Nr_softirqs}; 
Kernel defines 10 types of soft interrupts, including application to timer Tasklet Network Transceiver (NAPI) block device reading and writing.
As you can see from the comments, kernel does not want developers to add new SOFTIRQ, and if there is a need, you can take advantage of the Tasklet implemented by SOFTIRQ.


Let's look at SOFTIRQ's registration triggering and distribution processing

1 Soft Interrupt Registration

SOFTIRQ Registration uses the function OPEN_SOFTIRQ, similar to the REGISTER_IRQ of hardware interrupts. Defined in the KERNEL/SOFTIRQ.C

void Open_softirq (int nr, void (*action) (struct softirq_action *)) {    softirq_vec[nr].action = action;}
It is simple to add softirq_vec corresponding to the subscript of the processing function.

The SOFTIRQ of the timer is registered in the kernel startup Start_kernel as follows:
void __init init_timers (void) {    int err = Timer_cpu_notify (&TIMERS_NB, (unsigned long) cpu_up_prepare,                ( void *) (long) smp_processor_id ());    Init_timer_stats ();    BUG_ON (Err! = NOTIFY_OK);    Register_cpu_notifier (&TIMERS_NB);    OPEN_SOFTIRQ (TIMER_SOFTIRQ, RUN_TIMER_SOFTIRQ);}
Timer processing function is RUN_TIMER_SOFTIRQ, the following learning timer implementation will also be analyzed.

2 Soft Interrupt triggering

Unlike hardware interrupts that are triggered by hardware, soft interrupts are triggered by software, triggered by functions Raise_softirq and Raise_softirq_irqoff, and are implemented as follows:
inline void    Raise_softirq_irqoff (unsigned int nr) {__raise_softirq_irqoff (NR); /* * If we ' re in an interrupt or SOFTIRQ, we ' re do * (this also catches softirq-disabled code).     We'll * actually run the SOFTIRQ once we return from * the IRQ or SOFTIRQ.     * * Otherwise We wake up ksoftirqd to make sure we * schedule the SOFTIRQ soon. */if (!in_interrupt ()) wakeup_softirqd ();}    void Raise_softirq (unsigned int nr) {unsigned long flags;    Local_irq_save (flags);    Raise_softirq_irqoff (NR); Local_irq_restore (flags);}    void __raise_softirq_irqoff (unsigned int nr) {trace_softirq_raise (NR); Or_softirq_pending (1UL << nr);} 
The difference between the 2 functions is that RAISE_SOFTIRQ blocks the IRQ when the SOFTIRQ is triggered.
The trigger Softirq is called or_softirq_pending, and the kernel variable __softirq_pending the NR position bit.

So the __softirq_pending variable is similar to the interrupt State register INTC in a hardware interrupt. We can call it a soft interrupt state variable!

3 distribution processing of soft interrupts


Hardware interrupts are asynchronous to the processor, asynchronously to the software program. Hardware Interrupt trigger-Interrupt Exception entry-Interrupt distribution processing, hardware interrupt distribution processing time depends on the time of hardware interruption, the software does not need to control.
While soft interrupts cannot trigger calls asynchronously, the distribution handler for soft interrupts is DO_SOFTIRQ, and there are 3 main timing of distribution processing:
(1) After a hardware interrupt has been processed.
(2) in the KSOFTIRQD kernel thread.
(3) In code that explicitly checks and executes a soft interrupt to be processed, such as in a network subsystem (explicitly called DO_SOFTIRQ to send and receive packets).
We mainly look at the top 2 cases

(1) When the hardware interrupt processing function exits
When the interrupt handler exits, it calls Irq_exit, as in kernel/softirq.c:

static inline void Invoke_softirq (void) {if (!force_irqthreads) {#ifdef __arch_irq_exit_irqs_disabled __do_softirq (); #e                LSE DO_SOFTIRQ (); #endif} else {__local_bh_disable (unsigned long) __builtin_return_address (0),        Softirq_offset);        WAKEUP_SOFTIRQD ();    __local_bh_enable (Softirq_offset); }}/* * Exit an interrupt context.    Process Softirqs if needed and possible: */void irq_exit (void) {account_system_vtime (current);    Trace_hardirq_exit ();    Sub_preempt_count (Irq_exit_offset); if (!in_interrupt () && local_softirq_pending ()) Invoke_softirq (); #ifdef config_no_hz/* Make sure that T Imer wheel updates are propagated */if (IDLE_CPU (smp_processor_id ()) &&!in_interrupt () &&!need_resch    Ed ()) Tick_nohz_irq_exit (); #endif rcu_irq_exit (); Sched_preempt_enable_no_resched ();} 
Checks if the __softirq_pending has an offset, and INVOKE_SOFTIRQ calls DO_SOFTIRQ.

(2) KSOFTIRQD kernel thread
The implementation of this kernel thread is also in Kernel/softirq.c, where the code is not posted.
As you can see from the KSOFTIRQD threading implementation, kernel process KSOFTIRQD calls DO_SOFTIRQ to process them when there are a lot of soft interrupts in the kernel.

Soft interrupt distribution processing time is clear, let's see how DO_SOFTIRQ is handled in KERNEL/SOFTIRQ.C:
asmlinkage void Do_softirq (void) {    __u32 pending;    unsigned long flags;    if (In_interrupt ())        return;    Local_irq_save (flags);    Pending = Local_softirq_pending ();    if (pending)        __do_softirq ();    Local_irq_restore (flags);}
local_softirq_pending Gets the __softirq_pending soft interrupt state variable, and if there is a SOFTIRQ pending call __do_softirq, as follows:
#define Max_softirq_restart 10asmlinkage 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);    __local_bh_disable ((unsigned long) __builtin_return_address (0), softirq_offset);    Lockdep_softirq_enter ();    CPU = smp_processor_id (); restart:/* Reset the pending bitmask before enabling IRQs */set_softirq_pending (0);    Local_irq_enable ();    h = Softirq_vec;            Do {if (pending & 1) {unsigned int vec_nr = H-softirq_vec;            int prev_count = Preempt_count ();            KSTAT_INCR_SOFTIRQS_THIS_CPU (VEC_NR);            Trace_softirq_entry (VEC_NR);            H->action (h);            Trace_softirq_exit (VEC_NR);                       if (unlikely (prev_count! = Preempt_count ())) {PRINTK (kern_err "Huh, entered Softirq%u%s%p"              "With Preempt_count%08x,"         "Exited with%08x?\n", VEC_NR, Softirq_to_name[vec_nr], h->action,                Prev_count, Preempt_count ());            Preempt_count () = Prev_count;        } rcu_bh_qs (CPU);        } h++;    Pending >>= 1;    } while (pending);    Local_irq_disable ();    Pending = Local_softirq_pending ();    if (pending &&--max_restart) goto restart;    if (pending) Wakeup_softirqd ();    Lockdep_softirq_exit ();    Account_system_vtime (current); __local_bh_enable (Softirq_offset);}
__DO_SOFTIRQ takes and empties __softirq_pending before processing Softirq, and then calls the action handler function corresponding to Softirq_vec, based on pending traversal pending.
After the traversal is completed, the __softirq_pending is acquired again, and if the SOFTIRQ,__DO_SOFTIRQ is generated during the traversal of Softirq_vec, it jumps to restart to traverse the processing SOFTIRQ again.
Processing Max_softirq_restart times at most.
If there are SOFTIRQ pending, the KSOFTIRQD kernel thread is awakened to handle the remaining SOFTIRQ.

Soft Interrupt Registration trigger processing is so, soft interrupt is kernel implementation of pure software mechanism, relying on interrupt exit and kernel thread timing to do distribution processing.
based on the soft interrupt, kernel implements the timer Tasklet, the following is the key to see the implementation of the core timer principle.

One core timer
kernel timers are implemented through a combination of a kernel clock system and a soft interrupt.
The use of timers in driver is generally the case:

    static struct timer_list test_timer;    Init_timer (&test_timer);    Test_timer.function = (void *) test_handle_function;    Test_timer.data = (u32) test;    Test_timer.expires = Check_time + jiffies;    Add_timer (&test_timer);
the code initializes each member of the Timer_list, Timer_list represents a Timer object, and finally adds the timer_list to the kernel timer chain list tvec_bases.

Here's a look at how the kernel implements the timer.
1 Register Timer soft Interrupt
in front of the soft interrupt, Start_kernel init_timers registered the timer soft interrupt processing function RUN_TIMER_SOFTIRQ, soft interrupt number is TIMER_SOFTIRQ.

2 Trigger Timer soft interrupt
The trigger of the timer soft interrupt is in the kernel clock interrupt, according to the previous post "the Linux kernel clock system's past life" link address:
for Tickless Systems, the interrupt handler is Tick_nohz_handler, and in KERNEL/TIME/TICK-SCHED.C, the function calls Update_ in addition to updating the Xtime and setting the next trigger time. Process_times.
The function calls the Run_local_timers, as follows
void Run_local_timers (void) {    hrtimer_run_queues ();    RAISE_SOFTIRQ (TIMER_SOFTIRQ);}
where call RAISE_SOFTIRQ triggers a soft interrupt of the timer.

3 processing Timer soft Interrupt
depending on the previous handling of the soft interrupt, the hardware interrupt exits or ksoftirqd the DO_SOFTIRQ traversal Softirq_vec in the kernel thread.
because the timer soft interrupt is triggered, traversing Softirq_vec will call Softirq_action[timer_softirq].action, which is RUN_TIMER_SOFTIRQ.
RUN_TIMER_SOFTIRQ traverse all timers in tvec_bases timer_list, compare timer_list.expires with current jiffies, if consistent, indicate timed expiry, call Timer_ List.function.

the implementation of the kernel timer is similar to a two-level interrupt of a hardware interrupt, and we also determine the sub-module that is causing the interrupt in the module based on the interrupt status register in the module, based on the interrupt status register in the INTC.
The kernel timer is a soft interrupt that triggers the timer in the clock interrupt, the soft interrupt of the distribution processing timer when all hardware interrupts exit, the time expires, the timer processing function is executed, and finally the timer soft interrupt is cleared.


two Tasklet

1 Register Tasklet soft Interrupt
The Tasklet soft Interrupt handler is registered in Softirq_init in Start_kernel:
Open_softirq (TASKLET_SOFTIRQ, tasklet_action);

2 Register Tasklet
Tasklet can be statically created using one of the two macros defined in <linux/interrupt.h>, Declare_tasklet or declare_tasklet_disabled. The former sets the reference counter of the created Tasklet to 0 and the Tasklet is active. The other one sets the introduction counter to 1, so the tasklet is in a forbidden state.
You can also use Tasklet_init () to dynamically create a tasklet.

3 triggering and handling Tasklet soft interrupts
the operation that triggers the Tasklet soft interrupt is implemented by calling the RAISE_SOFTIRQ () function indirectly through the Tasklet_schedule () function.
after that, wait for any hardware interrupt handler to exit after calling Do_softirq to perform the TASKLET_SOFTIRQ soft interrupt handler function tasklet_action.
The tasket_action iterates through the Tasklet_vec list and executes its handler function for the Enable Tasklet.



The kernel timer Tasklet implementation is similar to a two-level interrupt for hardware interrupts.
Because the timer tasklet will check the execution processing when the hardware interrupt exits, it will be applied to interrupt the bottom half of the processing.
Interrupt processing requirements are as concise and fast as possible, so the time requirement is not very urgent, and some of the operations that are allowed to be performed later can be performed in the Tasklet and timer handler functions.




Implementation of Linux kernel soft interrupt and its derivative-timer Tasklet

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.