tasklet原理

tasklet是Linux内核中的可延迟执行机制,用于驱动程序的延迟操作。它基于软中断实现,但比软中断更灵活。tasklet在多处理器系统中确保同一tasklet不会在多个CPU上同时执行,通过tasklet_schedule()激活,tasklet_disable()和tasklet_enable()进行同步控制。
摘要由CSDN通过智能技术生成

tasklet是Linux内核中“可延迟执行”机制、或“中断下半部”的一种。基于软中断实现,但比软中断灵活,tasklet有的地方翻译作“任务蕾”,大部分书籍没找到合适的词汇去翻译它。本篇博客主要介绍tasklet的设计原理、使用方法。

本篇博客耗时8小时。

一、tasklet解决什么问题?

先看下tasklet在一些书籍上的介绍:

  • tasklet是I/O驱动程序中实现可延迟函数的首选方法(我猜某个内核版本开始,块设备从tasklet中独立出来成为单独的软中断BLOCK_SOFTIRQ和BLOCK_IOPOLL_SOFTIRQ)——ULK。
  • tasklet和工作队列是延期执行工作的机制,其实现基于软中断,但他们更易于使用,因而更适合与设备驱动程序...tasklet是“小进程”,执行一些迷你任务,对这些人物使用全功能进程可能比较浪费——PLKA。
  • tasklet是并行可执行(但是是锁密集型的)软件中断和旧下半区的一种混合体,这里既谈不上并行性,也谈不上性能。引入tasklet是为了替代原来的下半区。

下面这段来自于PLKA的话我也很想留在这里:软中断是将操作推迟到未来时刻执行的最有效的方法。但该延期机制处理起来非常复杂。因为多个处理器可以同时且独立的处理软中断,同一个软中断的处理程序可以在几个CPU上同时运行。对软中断的效率来说,这是一个关键,多处理器系统上的网络实现显然受惠于此。但处理程序的设计必须是完全可重入且线程安全的。另外,临界区必须用自旋锁保护(或其他IPC机制),而这需要大量审慎的考虑。

我自己的理解,由于软中断以ksoftirqd的形式与用户进程共同调度,这将关系到OS整体的性能,因此软中断在Linux内核中也仅仅就几个(网络、时钟、调度以及Tasklet等),在内核编译时确定。软中断这种方法显然不是面向硬件驱动的,而是驱动更上一层:不关心如何从具体的网卡接收数据包,但是从所有的网卡接收的数据包都要经过内核协议栈的处理。而且软中断比较“硬”——数量固定、编译时确定、操作函数必须可重入、需要慎重考虑锁的问题,不适合驱动直接调用,因此Linux内核为驱动直接提供了一种使用软中断的方法,就是tasklet。

二、tasklet数据结构

tasklet通过软中断实现,软中断中有两种类型属于tasklet,分别是级别最高的HI_SOFTIRQ和TASKLET_SOFTIRQ。

Linux内核采用两个PER_CPU的数组tasklet_vec[]和tasklet_hi_vec[]维护系统种的所有tasklet(kernel/softirq.c),分别维护TASKLET_SOFTIRQ级别和HI_SOFTIRQ级别的tasklet:

1

2

3

4

5

6

7

8

struct tasklet_head

{

struct tasklet_struct *head;

struct tasklet_struct **tail;

};

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);

static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

tasklet_vec

tasklet的核心结构体如下(include/linux/interrupt.h):

1

2

3

4

5

6

7

8

struct tasklet_struct

{

struct tasklet_struct *next;

unsigned long state;

atomic_t count;

void (*func)(unsigned long);

unsigned long data;

};

习惯上称之为tasklet描述符,func指针是具体的处理函数指针,data为可选参数,state表示该tasklet的状态,分别使用不同的bit表示两个状态:TASKLET_STATE_SCHED和TASKLET_STATE_RUN:

  • TASKLET_STATE_SCHED置位表示已经被调度(挂起),也意味着tasklet描述符被插入到了tasklet_vec和tasklet_hi_vec数组的其中一个链表中,可以被执行。
  • TASKLET_STATE_RUN置位表示该tasklet正在某个CPU上执行,单个处理器系统上并不校验该标志,因为没必要检查特定的tasklet是否正在运行。

count为原子计数器,用于禁用已经调度的tasklet,如果该值不为0,则不予以执行。

三、tasklet操作接口

tasklet对驱动开放的常用操作包括:

  • 初始化,tasklet_init(),初始化一个tasklet描述符。
  • 调度,tasklet_schedule()和tasklet_hi_schedule(),将taslet置位TASKLET_STATE_SCHED,并尝试激活所在的软中断。
  • 禁用/启动,tasklet_disable_nosync()、tasklet_disable()、task_enable(),通过count计数器实现。
  • 执行,tasklet_action()和tasklet_hi_action(),具体的执行软中断。
  • 杀死,tasklet_kill(),。。。

tasklet_int()函数实现如下(kernel/softirq.c):

1

2

3

4

5

6

7

8

9

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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值