Linux 软中断

it2026-01-20  14

本文转载自: http://blog.chinaunix.net/uid-9620812-id-3833377.html,如有需要,请移步访问。

Technorati 标签: Linux 软中断

---------------------------------------我是分割线----------------------------------------

一、软中断注册 和硬中断类似,软中断也有类似的中断向量表,只不过是用“软件”实现的。 struct softirq_action softirq_vec[32]是软中断向量表   (文件linux_2_6_24/kernel/softirq.c)

struct softirq_action{    void (*action)(struct softirq_action *); //钩子函数    void *data;                              //钩子函数的形参};

内核用到的中断向量(其实就是数组下标)如下所示 (文件linux_2_6_24/include/linux/interrupt.h)

enum{    HI_SOFTIRQ=0, //高优先级的tasklet    TIMER_SOFTIRQ,      //内核定时器    NET_TX_SOFTIRQ,     //网络发送    NET_RX_SOFTIRQ,     //网络接收    BLOCK_SOFTIRQ,      //???     TASKLET_SOFTIRQ,    //普通的tasklet    SCHED_SOFTIRQ}

内核注册一个软中断用函数,本质上就是就是初始化数组某一元素

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data){   //nr 即软中断向量编号    softirq_vec[nr].data = data;    softirq_vec[nr].action = action;}

内核注册软中断的地方有:

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)

二、软中断触发 前面注册完了,现在开始触发。 内核用一个数据结构来标记曾经有“软中断”发生过(或者说成软中断被触发过) __softirq_pending 共32bit,即每个bit对应软中断的一个向量,实际使用了6个bit 第n个bit置1,即softirq_vec[n]有软中断发生。

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)

常用的软中断触发函数

void raise_softirq_irqoff(int nr){    //nr 即软中断向量编号    __raise_softirq_irqoff(nr);}

但这只是“触发”软中断,软中断并不会立即被处理 三、软中断处理 函数_ _do_softirq是一次性按照向量表从高到低循环处理所有软中断(潜台词,软中断不可嵌套) _ _do_softirq()的调用时机: 1. irq_exit() 硬件中断处理完,返回时调用

do_IRQ() -->irq_exit()-->local_softirq_pending()-->_ _do_softirq()

2. ksoftirqd()  用于辅助处理软中断的内核线程,每一个CPU上都运行着一个ksoftirqd。

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()时,发现有待处理的软中断且当时没处在软硬中断上下文中

local_bh_enable()-->local_softirq_pending()-->_ _do_softirq()

处理过程代码详解

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); /*软中断处理中,禁止软中断再次进入,软中断处理是不可重入的*/    __local_bh_disable((unsigned long)__builtin_return_address(0));    trace_softirq_enter();    cpu = smp_processor_id();restart:/* Reset the pending bitmask before enabling irqs    下面首先清除pending,以便系统可以激活其它软件中断,    然后使能外部中断    系统在下面的处理中,将使能外部中断以提高系统的响应,    注意,必须先清除pending,再使能外部中断,否则死锁*/    set_softirq_pending(0);     local_irq_enable();     h = softirq_vec; /*下面按照从高到低调用open_softirq注册的句柄*/do {if (pending & 1) {h->action(h); //关键的一句,tasklet、内核timer、网络中断都是在这里搞的            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();}

转载于:https://www.cnblogs.com/cherishui/p/4318660.html

相关资源:数据结构—成绩单生成器
最新回复(0)