Linux kernel source scenario analysis-interrupt lower half (soft interrupt)

Source: Internet
Author: User
Tags goto

Tasklet mechanism is a kind of special soft interrupt. The original meaning of the word tasklet is "small task", here refers to a small piece of executable code, and usually in the form of a function. The soft interrupt vectors HI_SOFTIRQ and TASKLET_SOFTIRQ are implemented by Tasklet mechanism.
In a way, the tasklet mechanism is an extension of the Linux kernel to the BH mechanism. After the introduction of the SOFTIRQ mechanism in the 2.4 kernel, the original BH mechanism is incorporated into the overall framework of the SOFTIRQ mechanism through the tasklet mechanism. It is precisely because of this historical extension relationship that the Tasklet mechanism differs from the general sense of soft interruption, and presents the following two notable features:
1. Unlike a typical soft interrupt, a section of Tasklet code can run on only one CPU at a time, rather than a general soft interrupt service function (that is, the action function pointer in the SOFTIRQ_ACTION structure)--at the same time, it may be executed concurrently by multiple CPUs.
2. Unlike the BH mechanism, different tasklet codes can be executed concurrently on multiple CPUs at the same time , unlike the BH mechanism, which must be strictly serialized (that is, only one CPU can perform BH functions in the system at the same time).

Soft Interrupt is the argument that interrupts the lower half, the tasklet mechanism is a special example of soft interrupts, and the soft interrupt vectors HI_SOFTIRQ and TASKLET_SOFTIRQ are implemented by Tasklet mechanism. Finally BH is incorporated into the soft interrupt framework through the tasklet mechanism.


First, the initialization of soft interrupts

1. Initialize the tasklet mechanism

void __init Softirq_init () {int i;for (i=0; i<32; i++) Tasklet_init (bh_task_vec+i, bh_action, i); OPEN_SOFTIRQ (Tasklet _SOFTIRQ, tasklet_action, null); Open_softirq (HI_SOFTIRQ, tasklet_hi_action, null);}
struct tasklet_struct{struct tasklet_struct *next;unsigned long state;atomic_t count;void (*func) (unsigned long); unsigned long data;};
struct tasklet_struct bh_task_vec[32];
ENUM{HI_SOFTIRQ=0,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,TASKLET_SOFTIRQ};

The Tasklet_init function is as follows:

void Tasklet_init (struct tasklet_struct *t,  Void (*func) (unsigned long), unsigned Long data) {T->func = func;t- >data = Data;//0~32t->state = 0;atomic_set (&t->count, 0);}


The OPEN_SOFTIRQ function is as follows:

void Open_softirq (int nr, void (*action) (struct softirq_action*), void *data) {unsigned long flags;int i;spin_lock_ Irqsave (&softirq_mask_lock, flags); softirq_vec[nr].data = Data;softirq_vec[nr].action = Action;for (i=0; i<NR_ CPUS; i++)//nr_cpus is 1softirq_mask (i) |= (1<<NR),//irq_stat[0].__softirq_mask 1th and 4th place 1spin_unlock_irqrestore ( &softirq_mask_lock, flags);}
struct Softirq_action{void (*action) (struct softirq_action *); void*data;};
static struct softirq_action softirq_vec[32] __cacheline_aligned;
#define SOFTIRQ_MASK (CPU) __irq_stat (CPU), __softirq_mask
#define __IRQ_STAT (CPU, member) ((void) (CPU), Irq_stat[0].member)
typedef struct {unsigned int __softirq_active;unsigned int __softirq_mask;unsigned int __local_irq_count;unsigned int __ local_bh_count;unsigned int __syscall_count;unsigned int __nmi_count;/* arch Dependent */} ____cacheline_aligned Irq_ cpustat_t;
extern irq_cpustat_t irq_stat[];


2. Initialize BH

void __init sched_init (void) {/* * * We have to do a little magic to get the first * process right in SMP mode. */......init_ BH (TIMER_BH, TIMER_BH); Init_bh (TQUEUE_BH, TQUEUE_BH); Init_bh (IMMEDIATE_BH, IMMEDIATE_BH);/* * The boot idle thread does Lazy MMU Switching as well: */atomic_inc (&init_mm.mm_count); Enter_lazy_tlb (&init_mm, current, CPU);}
enum {timer_bh = 0,tqueue_bh,digi_bh,serial_bh,riscom8_bh,specialix_bh,aurora_bh,esp_bh,scsi_bh,immediate_bh, CYCLADES_BH,CM206_BH,JS_BH,MACSERIAL_BH,ISICOM_BH};
void Init_bh (int nr, void (*routine) (void)) {Bh_base[nr] = ROUTINE;MB ();}

Ii. linking the TASKLET_STRUCT structure (bh_task_vec+0) into the tasklet_hi_vec[0]

In the clock processing function, MARK_BH (TIMER_BH) is executed in Do_timer, and the code is as follows:

static inline void mark_bh (int nr) {tasklet_hi_schedule (BH_TASK_VEC+NR);}
static inline void Tasklet_hi_schedule (struct tasklet_struct *t) {if (!test_and_set_bit (tasklet_state_sched, &t- >state)) {int CPU = SMP_PROCESSOR_ID (); unsigned long flags;local_irq_save (flags); t->next = Tasklet_hi_vec[cpu]. list;//links the tasklet_struct structure (bh_task_vec+0) into tasklet_hi_vec[0]tasklet_hi_vec[cpu].list = T;__CPU_RAISE_SOFTIRQ (CPU, HI_SOFTIRQ); Local_irq_restore (flags);}}
struct tasklet_head{struct tasklet_struct *list;} __attribute__ ((__aligned__ (smp_cache_bytes)));
extern struct Tasklet_head Tasklet_hi_vec[nr_cpus];//nr_cpus is 0
static inline void __cpu_raise_softirq (int cpu, int nr) {softirq_active (CPU) |= (1<<NR);//irq_stat[0].__softirq_ Active 1th Place 1}

Third, soft interrupt response

Each time the kernel executes the Interrupt service program in a channel in DO_IRQ (), and whenever it returns from a system call, it checks to see if there is a soft interrupt request waiting to be executed.

       if (softirq_active (CPU) & Softirq_mask (CPU))//irq_stat[0].__softirq_active 1th position 1 & irq_stat[0].__softirq_ Mask 1th and 4th digit 1 result not 0           DO_SOFTIRQ ();  


The DO_SOFTIRQ code is as follows:

asmlinkage void Do_softirq () {int CPU = SMP_PROCESSOR_ID () __u32 active, Mask;if (In_interrupt ())//If the irq_stat[0]._ has been added The _local_bh_count count, which has not been subtracted, then returns directly, i.e. return;local_bh_disable ();//Increase Irq_stat[0].__local_bh_count count local_irq_ Disable ();//cli off Interrupt mask = Softirq_mask (CPU); active = Softirq_active (CPU) & Mask;if (active) {struct softirq_action *h ; restart:/* Reset active bitmask before enabling IRQs */softirq_active (CPU) &= ~active;local_irq_enable ();//sti on interrupt H = Softirq_vec;mask &= ~active;do {if (Active & 1) h->action (h);//execute tasklet_hi_actionh++;active >>= 1;} while (active); local_irq_disable (); active = softirq_active (CPU); if (active &= mask)! = 0) goto retry;} Local_bh_enable ();////reduce irq_stat[0].__local_bh_count count/* Leave with locally disabled hard IRQs. It's critical to close * windows for infinite recursion, while we help local BH count, * it protected us. Now we is defenceless. */return;retry:goto Restart;}
#define Local_bh_disable () cpu_bh_disable (smp_processor_id ())
#define CPU_BH_DISABLE (CPU) do {Local_bh_count (CPU) + +, barrier ();} while (0)
#define LOCAL_BH_COUNT (CPU) __irq_stat (CPU), __local_bh_count
#define __IRQ_STAT (CPU, member) ((void) (CPU), Irq_stat[0].member)
#define IN_INTERRUPT () ({int __cpu = smp_processor_id (); (Local_irq_count (__CPU) + local_bh_count (__cpu)! = 0); })
If an interrupt occurs during the execution of the DO_SOFTIRQ, the DO_SOFTIRQ is executed on the same CPU, and at in_interrupt time, it returns immediately. Therefore, the tasklet mechanism is prevented from executing the nesting of programs.


Tasklet_hi_action, the function is as follows:

static void Tasklet_hi_action (struct softirq_action *a) {int cpu = smp_processor_id (); struct tasklet_struct *list;local_ Irq_disable (); list = Tasklet_hi_vec[cpu].list;tasklet_hi_vec[cpu].list = Null;local_irq_enable (); while (list! = NULL) {struct Tasklet_struct *t = List;list = List->next;if (Tasklet_trylock (t)) {if (Atomic_read (&t->count) = = 0) {CL Ear_bit (tasklet_state_sched, &t->state); T->func (T->data); Tasklet_unlock (t); continue;} Tasklet_unlock (t);} Local_irq_disable (); t->next = Tasklet_hi_vec[cpu].list;tasklet_hi_vec[cpu].list = T;__cpu_raise_softirq (CPU, HI_ SOFTIRQ); local_irq_enable ();}}

Just link the tasklet_struct structure (bh_task_vec+0) into tasklet_hi_vec[0], take it out, execute T->func (t->data), i.e. bh_action (0), the code is as follows:

static void Bh_action (unsigned long nr) {int cpu = SMP_PROCESSOR_ID (), if (!spin_trylock (&global_bh_lock))//Global lock, Only one CPU in the system can perform the BH function goto resched;if (!hardirq_trylock (CPU)) goto resched_unlock;if (BH_BASE[NR]) BH_BASE[NR] () at the same time;// The last execution is bh_base[0], i.e. timer_bhhardirq_endlock (CPU); Spin_unlock (&global_bh_lock); return;resched_unlock:spin_ Unlock (&global_bh_lock); Resched:mark_bh (NR);}


If T->func (t->data) is not bh_action (0), also is not BH function , then tasklets mechanism satisfies:
1.A section of Tasklet code can run on only one CPU at a time.

2 . Different tasklet codes can be executed concurrently on multiple CPUs at the same time.

if T->func (t->data) is bh_action (0), which is the BH function , must be strictly serialized as the BH mechanism (i.e. only one CPU can perform BH functions in the system at the same time).  

So BH is integrated into the soft interrupt framework through the tasklet mechanism.

Linux kernel source scenario analysis-interrupt lower half (soft interrupt)

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.