本文转载自: 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
相关资源:数据结构—成绩单生成器