linux的软中断
本来没想到写这个的,但在研究linux的动态定时器时,发现动态定时器是用到软中断机制的,所以对软中断做一个浅显的了解: 在分析过程中,愈加的觉得kernel是一个整体,想单单搞懂驱动是有难度的,因为kernel是个整体。你要懂驱动,就要对驱动模型,就要对文件系统、内存管理和进程调度等等有一定了解。 下面来分析soft irq:在kernel/softirq.c中:
本来没想到写这个的,但在研究linux的动态定时器时,发现动态定时器是用到软中断机制的,所以对软中断做一个浅显的了解:
在分析过程中,愈加的觉得kernel是一个整体,想单单搞懂驱动是有难度的,因为kernel是个整体。你要懂驱动,就要对驱动模型,就要对文件系统、内存管理和进程调度等等有一定了解。
下面来分析soft irq:
在kernel/softirq.c中:
staticstruct softirq_action softirq_vec[NR_SOFTIRQS]__cacheline_aligned_in_smp;
这就是软中断的中断向量表。
还有一个枚举变量:
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 be the last softirq */
NR_SOFTIRQS
};
内核用这些从 0开始的索引来表示一种相对优先级。索引号小的软中断在索引号大的软中断之前执行。
TIMER_SOFTIRQ的索引值是1,优先值是很高的。
软中断的注册:
open_softirq(TIMER_SOFTIRQ, run_timer_softirq); void open_softirq(int nr, void (*action)(struct softirq_action *)) { softirq_vec[nr].action = action; }
这里将TIMER_SOFTIRQ软中断索引号与run_timer_softirq中断处理程序联系起来。
软中断的触发:
内核在硬件时钟中断发生后执行定时器,定时器作为软中断在下半部上下文中执行。具体的情况是:时钟中断处理程序会执行update_process_times()函数,该函数调用run_local_timers()函数:
void run_local_timers(void) { hrtimer_run_queues(); raise_softirq(TIMER_SOFTIRQ); softlockup_tick(); }
inline void raise_softirq_irqoff(unsigned int nr) { __raise_softirq_irqoff(nr); /* * If we're in an interrupt or softirq, we're done * (this also catches softirq-disabled code). We will * 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); }
在注释中有这么一句:Otherwise we wake up ksoftirqd to make sure we schedule the softirq soon
唤醒ksoftirqd内核线程来保证调度立即执行softirq
软中断的执行:
在kernel/softirq.c中:
staticint __cpuinit cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
中,建立一个ksoftirqd内核线程来执行软中断:
kthread_create(run_ksoftirqd,hcpu, "ksoftirqd/%d", hotcpu);
在run_ksoftirqd当中,
run_ksoftirqd-->do_softirq-->__do_softirq
__do_softirq函数的核心部分如下:
h = softirq_vec; do { if (pending & 1) { int prev_count = preempt_count(); kstat_incr_softirqs_this_cpu(h - softirq_vec); trace_softirq_entry(h, softirq_vec); h->action(h); trace_softirq_exit(h, softirq_vec); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %s %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, softirq_to_name[h - softirq_vec], h->action, prev_count, preempt_count()); preempt_count() = prev_count; } rcu_bh_qs(cpu); } h++; pending >>= 1; } while (pending);
大致看出这个过程是循环遍历每一个待处理的软中断,调用它们的中断处理程序。
这样,利用了软中断,我们的run_timer_softirq这个中断处理程序得以运行。
对这个linux软中断的分析比较简单,仅仅为linux的动态定时器做了铺垫。后面还需要再仔细分析linux的软中断。
更多推荐
所有评论(0)