本来没想到写这个的,但在研究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的软中断。











Logo

更多推荐