《深入理解Linux内核》第四章 中断和异常(四)

上篇讲完了softirq,今天让我们来看一个softirq应用实例-------tasklet

二、tasklet

1、优点

1、简单易用,在设备驱动中比较常见

2、同softirq一样,tasklet执行期间,中断处于使能

2、特点

1、动态分配

2、同一种tasklet不能同时在多个CPU上运行,但是不同的tasklet,可以同时在多个CPU上运行

3、tasklet种类

1、HI_SOFTIRQ,对应0号softirq

2、TASKLET_SOFTIRQ,对应5号softirq

两者除了调用顺序有先后外(先调用HI_SOFTIRQ,再调用TASKLET_SOFTIRQ),其余均相同

4、数据结构

/* Tasklets --- multithreaded analogue of BHs.

   Main feature differing them of generic softirqs: tasklet
   is running only on one CPU simultaneously.

   Main feature differing them of BHs: different tasklets
   may be run simultaneously on different CPUs.

   Properties:
   * If tasklet_schedule() is called, then tasklet is guaranteed
     to be executed on some cpu at least once after this.
   * If the tasklet is already scheduled, but its excecution is still not
     started, it will be executed only once.
   * If this tasklet is already running on another CPU (or schedule is called
     from tasklet itself), it is rescheduled for later.
   * Tasklet is strictly serialized wrt itself, but not
     wrt another tasklets. If client needs some intertask synchronization,
     he makes it with spinlocks.
 */

struct tasklet_struct
{
	struct tasklet_struct *next;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long);
	unsigned long data;
};

/* Tasklets */
struct tasklet_head
{
	struct tasklet_struct *list;
};


static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL }

5、使用方法

1、动态分配tasklet_struct

2、tasklet_init()

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;
}

填充tasklet_struct结构体中各个字段 

3、tasklet_schedule()

void fastcall __tasklet_schedule(struct tasklet_struct *t)
{
	unsigned long flags;

	local_irq_save(flags);
	t->next = __get_cpu_var(tasklet_vec).list;
	__get_cpu_var(tasklet_vec).list = t;
	raise_softirq_irqoff(TASKLET_SOFTIRQ);
	local_irq_restore(flags);
}

EXPORT_SYMBOL(__tasklet_schedule)

static inline void tasklet_schedule(struct tasklet_struct *t)
{
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}

1、测试tasklet是否处于TASKLET_STATE_SCHED状态,如果没有处于,则置位state中TASKLET_STATE_SCHED bit,否则直接退出

2、将tasklet_struct结构体指针t赋值给当前CPU对应tasklet_vec中list字段

3、raise_softirq_irqoff()具体实现请参考https://blog.csdn.net/yxw0609131056/article/details/110004548 《深入理解Linux内核》第四章中断和异常(三),将当前CPU对应的irq_cpustat_t中__softirq_pending字段对应的bit TASKLET_SOFTIRQ置位。

4、当系统运行到softirq检查点时,就会调用do_softirq()

do_softirq()具体实现请参考https://blog.csdn.net/yxw0609131056/article/details/110004548 《深入理解Linux内核》第四章中断和异常(三)

5、在__do_softirq()中,就会调用h->action(h),

原来系统在初始化时,已经将action()指定为 tasklet_action()

void __init softirq_init(void)
{
	open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
	open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}

6、tasklet_action()

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

	local_irq_disable();
	list = __get_cpu_var(tasklet_vec).list;
	__get_cpu_var(tasklet_vec).list = NULL;
	local_irq_enable();

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

		list = list->next;

		if (tasklet_trylock(t)) {
			if (!atomic_read(&t->count)) {
				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
					BUG();
				t->func(t->data);
				tasklet_unlock(t);
				continue;
			}
			tasklet_unlock(t);
		}

		local_irq_disable();
		t->next = __get_cpu_var(tasklet_vec).list;
		__get_cpu_var(tasklet_vec).list = t;
		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
		local_irq_enable();
	}
}

1、首先获得当前CPU对应tasklet_vec中list字段,赋值给list变量,并将其清空

2、如果list不为空,则说明有tasklet请求产生,需要进一步处理,否则直接退出

3、判断tasklet是否处于TASKLET_STATE_RUN并测试tasklet_struct结构体count字段,如果成功,则清除state中TASKLET_STATE_SCHED bit,否则直接跳到6

4、调用用户注册的func()

5、如果前面tasklet处于TASKLET_STATE_RUN,则清除TASKLET_STATE_RUN bit

6、重新设置当前CPU对应tasklet_vec中list字段,重新产生TASKLET_SOFTIRQ

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《深入理解Linux内核》是一本经典的操作系统内核相关的书籍,它详细介绍了Linux内核的结构、逻辑和功能,为读者深入理解Linux操作系统提供了重要的参考。 第版中文版epub的出版,不仅极大地方便了读者在电子设备上阅读学习,还将经典的内核学习资源带给更多、更广泛的读者,让更多的人通过它深入理解Linux内核。 该书主要包括内核基础、进程管理、进程间通信、系统调用、中断异常、设备驱动程序、文件系统等多个部分,通过深入讲解每个部分的特点和实现原理,为读者打开了Linux内核的大门,让其能够全面深入地了解Linux操作系统。 在学习的过程中,读者需要具备一定的操作系统和编程基础,但是,即使是初学者,也可以通过本书的详细讲解和案例研究逐步掌握操作系统内核的相关知识。 总之,对于学习操作系统内核知识的读者,这本书是一个不可或缺的重要资源,而第版中文版epub的发布,更是进一步扩展了该书的影响范围,为更多读者带来了便利和学习机会。 ### 回答2: 《深入理解Linux内核》第版是一本图书,主要介绍了Linux内核的运作原理和实现机制。它详细介绍了内核底层的数据结构、内存管理、进程调度、文件系统、网络协议栈、设备驱动等方面的知识,并提供了丰富的代码示例以帮助读者更好地理解。本书是日本著名的内核开发者Masami Hiramatsu和Takatoshi Kondo所著的,由于其权威性、详细性和实用性而备受欢迎。 本书适合具有一定Linux系统编程和操作经验的读者。对于想要从事Linux内核开发、系统调优、性能优化、驱动编写等方面的人员来说,本书是一本绝佳的参考书。此外,本书还能帮助读者更好地理解其他Linux系统相关的书籍和文档。 本书以深入浅出的方式,循序渐进地介绍了Linux内核的各个方面,同时也提供了丰富的例子和实用的技巧。读者可以从中掌握Linux内核的基本原理和实现方法,以及如何进行Linux系统的调优和优化。 总之,《深入理解Linux内核》第版是一本权威、实用、详细的图书,对于想要更深入了解Linux内核的读者,是一本不可缺少的参考书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值