ImageVerifierCode 换一换
格式:DOCX , 页数:9 ,大小:18.86KB ,
资源ID:5255560      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5255560.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(tasklet原理.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

tasklet原理.docx

1、tasklet原理 tasklet原理tasklet是Linux内核中“可延迟执行”机制、或“中断下半部”的一种。基于软中断实现,但比软中断灵活,tasklet有的地方翻译作“任务蕾”,大部分书籍没找到合适的词汇去翻译它。本篇博客主要介绍tasklet的设计原理、使用方法。一、tasklet解决什么问题?先看下tasklet在一些书籍上的介绍:tasklet是I/O驱动程序中实现可延迟函数的首选方法(我猜某个内核版本开始,块设备从tasklet中独立出来成为单独的软中断BLOCK_SOFTIRQ和BLOCK_IOPOLL_SOFTIRQ)ULK。tasklet和工作队列是延期执行工作的机制,其

2、实现基于软中断,但他们更易于使用,因而更适合与设备驱动程序.tasklet是“小进程”,执行一些迷你任务,对这些人物使用全功能进程可能比较浪费PLKA。tasklet是并行可执行(但是是锁密集型的)软件中断和旧下半区的一种混合体,这里既谈不上并行性,也谈不上性能。引入tasklet是为了替代原来的下半区。下面这段来自于PLKA的话我也很想留在这里:软中断是将操作推迟到未来时刻执行的最有效的方法。但该延期机制处理起来非常复杂。因为多个处理器可以同时且独立的处理软中断,同一个软中断的处理程序可以在几个CPU上同时运行。对软中断的效率来说,这是一个关键,多处理器系统上的网络实现显然受惠于此。但处理程

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

4、中断的方法,就是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:struct tasklet_headstruct tasklet_struct *head;struct tasklet_struct *tail;sta

5、tic DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);tasklet_vectasklet的核心结构体如下(include/linux/interrupt.h):struct tasklet_structstruct tasklet_struct *next;unsigned long state;atomic_t count;void (*func)(unsigned long);unsigned long data;习惯上

6、称之为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为原子计数

7、器,用于禁用已经调度的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

8、(),具体的执行软中断。杀死,tasklet_kill(),。tasklet_int()函数实现如下(kernel/softirq.c):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_schedule()函数与tasklet_hi_schedule()函数的实现很类似,这里只列tasklet

9、_schedule()函数的实现(kernel/softirq.c),都挺明白就不描述了:static inline void tasklet_schedule(struct tasklet_struct *t)if (!test_and_set_bit(TASKLET_STATE_SCHED, &t-state)_tasklet_schedule(t);void _tasklet_schedule(struct tasklet_struct *t)unsigned long flags;local_irq_save(flags);t-next = NULL;*_this_cpu_read(t

10、asklet_vec.tail) = t;_this_cpu_write(tasklet_vec.tail, &(t-next);raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_restore(flags);tasklet_disable()函数、task_enable()函数以及tasklet_disable_nosync()函数(include/linux/interrupt.h),不说了只列代码:static inline void tasklet_disable_nosync(struct tasklet_struct *t)atomic

11、_inc(&t-count);smp_mb_after_atomic_inc();static inline void tasklet_disable(struct tasklet_struct *t)tasklet_disable_nosync(t);tasklet_unlock_wait(t);smp_mb();static inline void tasklet_enable(struct tasklet_struct *t)smp_mb_before_atomic_dec();atomic_dec(&t-count);只列tasklet_action()函数(kernel/softir

12、q.c):static void tasklet_action(struct softirq_action *a)struct tasklet_struct *list;local_irq_disable();list = _this_cpu_read(tasklet_vec.head);_this_cpu_write(tasklet_vec.head, NULL);_this_cpu_write(tasklet_vec.tail, &_get_cpu_var(tasklet_vec).head);local_irq_enable();while (list) struct tasklet_s

13、truct *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 = NULL;*_this_cpu_read(tasklet_vec.tail) = t;_this_cpu_write(tasklet_v

14、ec.tail, &(t-next);_raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_enable();tasklet_action()函数在softirq_init()函数中被调用:void _init softirq_init(void).open_softirq(TASKLET_SOFTIRQ, tasklet_action);open_softirq(HI_SOFTIRQ, tasklet_hi_action);tasklet_kill()实现:void tasklet_kill(struct tasklet_struct *t)if

15、(in_interrupt()printk(Attempt to kill tasklet from interruptn);while (test_and_set_bit(TASKLET_STATE_SCHED, &t-state) do yield(); while (test_bit(TASKLET_STATE_SCHED, &t-state);tasklet_unlock_wait(t);clear_bit(TASKLET_STATE_SCHED, &t-state);yeild()函数是个值的研究的点。四、一个tasklet调用例子找了一个tasklet的例子看一下(drivers/

16、usb/atm,usb摄像头),在其自举函数usbatm_usb_probe()中调用了tasklet_init()初始化了两个tasklet描述符用于接收和发送的“可延迟操作处理”,但此是并没有将其加入到tasklet_vec或tasklet_hi_vec中:tasklet_init(&instance-rx_channel.tasklet,usbatm_rx_process, (unsigned long)instance);tasklet_init(&tance -tx_channel.tasklet,usbatm_tx_process, (unsigned long)instance)

17、;在其发送接口usbatm_atm_send()函数调用tasklet_schedule()函数将所初始化的tasklet加入到当前cpu的tasklet_vec链表尾部,并尝试调用do_softirq_irqoff()执行软中断TASKLET_SOFTIRQ:static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb).tasklet_schedule(&instance-tx_channel.tasklet);.在其断开设备的接口usbatm_usb_disconnect()中调用tasklet_disable()

18、函数和tasklet_enable()函数重新启动其收发tasklet(具体原因不详,这个地方可能就是由这个需要,暂时重启收发tasklet):void usbatm_usb_disconnect(struct usb_interface *intf).tasklet_disable(&instance-rx_channel.tasklet);tasklet_disable(&instance-tx_channel.tasklet);.tasklet_enable(&instance-rx_channel.tasklet);tasklet_enable(&instance-tx_channel

19、.tasklet);.在其销毁接口usbatm_destroy_instance()中调用tasklet_kill()函数,强行将该tasklet踢出调度队列。从上述过程以及tasklet的设计可以看出,tasklet整体是这么运行的:驱动应该在其硬中断处理函数的莫为调用tasklet_schedule()接口激活该taskle,内核经常调用do_softirq()执行软中断,通过softirq执行tasket,如下图所示。图中灰色部分为禁止硬中断部分,为保护软中断pending位图和tasklet_vec链表数组,count的改变均为原子操作,count确保SMP架构下同时只有一个CPU在执

20、行该tasklet:tasklet_action五、tasklet同步主要看两个参数,一个state,一个count。state用于校验在tasklet_action()或tasklet_schedule()时,是否执行该tasklet的handler。state被tasklet_schedule()函数、tasklet_hi_schedule()函数、tasklet_action()函数以及tasklet_kill()函数所修改:tasklet_schedule()函数、tasklet_hi_schedule()函数将state置位TASKLET_STATE_SCHED。tasklet_ac

21、tion()函数将state的TASKLET_STATE_SCHED清除,并设置TASKLET_STATE_RUN。tasklet_kill()函数将state的TASKLET_STATE_SCHED清除。tasklet_action()函数在设置TASKLET_STATE_RUN标志时,使用了tasklet_trylock()、tasklet_unlock()等接口: count用于smp同步,count不为0,则表示该tasklet正在某CPU上执行,其他CPU则不执行该tasklet,count保证某个tasklet同时只能在一个CPU上执行。count的操作都是原子操作:tasklet

22、_disable()函数/tasklet_disable_nosync()函数将count原子减1。tasklet_enablle()函数将count原子加1。 另外,tasklet的操作中还所使用了local_irq_save()/local_irq_disable()等禁止本地中断的函数,早保护对象被修改完毕后立即使用local_irq_resore()/local_irq_enable()开启:tasklet_schedule()函数中,用于保护tasklet_vec链表和软中断的pending位图的更改。因为硬中断的激发能导致二者的更改。tasklet_action()函数中,用于保护

23、tasklet_vec链表和软中断的pending位图的更改。因为硬中断的激发能导致二者的更改。六、总结tasklet是一种“可延迟执行”机制中的一种,基于软中断实现,主要面向驱动程序。tasklet与软中断的区别在于每个CPU上不能同时执行相同的tasklet,tasklet函数本身也不必是可重入的。与软中断一样,为了保证tasklet和硬中断之间在同一个CPU上是串行执行的,维护其PER_CPU的链表时,需要屏蔽硬中断。不要为了列代码而列代码,不要为了抄书而抄书。七、细节1、原子操作tasklet使用taskle_disable()函数和tasklet_enable()函数对count位进

24、行增减操作,以保证SMP架构下,不在不同的CPU上同时运行相同的tasklet。这里使用了原子操作atomic_inc()和atomic_dec():static inline void atomic_inc(atomic_t *v)asm volatile(LOCK_PREFIX incl %0: +m (v->counter);static inline void atomic_dec(atomic_t *v)asm volatile(LOCK_PREFIX decl %0: +m (v->counter);#ifdef CONFIG_SMP#define LOCK_PREFIX_HERE.pushsection .smp_locks,an.balign 4n.long 671f - .n /* offset */.popsectionn671:#define LOCK_PREFIX LOCK_PREFIX_HERE ntlock; #else /* ! CONFIG_SMP */#define LOCK_PREFIX_HERE #define LOCK_PREFIX #endif

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1