当前位置: 首页 > 工具软件 > Tasklet > 使用案例 >

tasklet

怀晋
2023-12-01

tasklet是一种软中断,是基于softirq的基础演变而来的,但是由于资源的限制,softirq是在内核里面预定义好的,无法改变其种类,若要改变的话,就要修改内核代码,这对于驱动开发来说不是很合适.因此基于softirq发展出的tasklet来动态的改变中断的种类,这些中断使用链表连接起来,一旦发生了TASKLET_SOFTIRQ中断(tasklet对应的软中断类型),就按照链表的顺序依次全部执行,执行完毕就断开链表.

使用tasklet方法

//首先调用tasklet_init函数,对tasklet_struct 结构体进行初始化
void tasklet_init(struct tasklet_struct *t,
		  void (*func)(unsigned long), unsigned long data)
{
	t->next = NULL;
	t->state = 0;
	atomic_set(&t->count, 0);
	t->func = func;
	t->data = data;
}

struct tasklet_struct
{
	struct tasklet_struct *next; //链表指向的下一个目标
	unsigned long state; 
	atomic_t count;
	void (*func)(unsigned long); //中断函数
	unsigned long data; //传递给中断函数的参数
};
//然后触发tasklet中断,引起调度
static inline void tasklet_schedule(struct tasklet_struct *t)
{
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}

因为tasklet不同于softirq,softirq允许同一个中断函数在不同的CPU上面执行,但是要保证中断函数的可重入性.tasklet就正好相反,本身就带有锁机制,也就是tasklet_struct的state域,用于同步中断函数的执行,自然就不能同时在多个CPU上面执行了,这样就简化了我们中断函数的编写,不需要考虑到额外的同步问题.至于tasklet_struct的count域是用于屏蔽掉当前tasklet中断,这可以从tasklet_disable这个函数的内容看出.

tasklet既然是一种softirq,那就一定要注册相应的软中断函数:

void __init softirq_init(void)
{
	int cpu;
	/*因为是哪个处理器触发的软中断就由哪个处理器处理中断函数
	* 因此,每个处理器都要添加相应的结构
	*/
	for_each_possible_cpu(cpu) {
		int i;

		per_cpu(tasklet_vec, cpu).tail =
			&per_cpu(tasklet_vec, cpu).head;
		per_cpu(tasklet_hi_vec, cpu).tail =
			&per_cpu(tasklet_hi_vec, cpu).head;
		for (i = 0; i < NR_SOFTIRQS; i++)
			INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
	}

	register_hotcpu_notifier(&remote_softirq_cpu_notifier);

	open_softirq(TASKLET_SOFTIRQ, tasklet_action);
	open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

上面代码显示tasklet_action就是相应的中断函数

static void tasklet_action(struct softirq_action *a)
{
	struct tasklet_struct *list;

	local_irq_disable();
	/*每个cpu都有一个关于tasklet链表的头和尾,用于中 tasklet中断的处理*/
	list = __get_cpu_var(tasklet_vec).head;
	__get_cpu_var(tasklet_vec).head = NULL;
	__get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
	local_irq_enable();

	while (list) {
		struct tasklet_struct *t = list;

		list = list->next;
		/*检查是否已经被正在执行,即检查(t)->state的TASKLET_STATE_RUN位是否被置位
		* 若已置位说明这个中断函数正在被其他的cpu执行
		*/
		if (tasklet_trylock(t)) {
			//检查当前tasklet是否被disable掉了
			if (!atomic_read(&t->count)) {
				//检查当前的tasklet是否是pending状态,如果是的话,就执行中断函数
				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
					BUG();
				t->func(t->data);
				tasklet_unlock(t);
				continue;
			}
			tasklet_unlock(t);
		}
		/*因为上面有一个continue语句,因此对于运行到这里的函数说明上面的判断
		* 语句有不满足的情况,第一种情况:当前函数被其他的cpu执行;第二种情况:
		* 当前中断被disable了;对于这两种情况都会把他们重新加入到链表的尾部
		* 然后重新唤醒TASKLET_SOFTIRQ,等到有空再次执行这些中断函数
		*/
		local_irq_disable();
		t->next = NULL;
		*__get_cpu_var(tasklet_vec).tail = t;
		__get_cpu_var(tasklet_vec).tail = &(t->next);
		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
		local_irq_enable();
	}
}
 类似资料: