微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux 2.4.x内核软中断机制

Linux 2.4.x内核软中断机制

时间:04-06 来源: 点击:

动; tq_immediate,在中断返回前以及schedule()函数中启动; tq_disk,内存管理模块内部使用。

一般使用tq_immediate就可以完成大多数异步任务了。

run_task_queue(task_queue *list)函数可用于启动list中挂接的所有task,可以手动调用,也可以挂接在上面提到的bottom half向量表中启动。以run_task_queue()作为bh_base[nr]的函数指针,实际上就是扩充了每个bottom half的函数句柄数,而对于系统预定义的tq_timer和tq_immediate的确是分别挂接在TQUEUE_BH和IMMEDIATE_BH上(注意,TIMER_BH没有如此使用,但TQUEUE_BH也是在do_timer()中启动的),从而可以用于扩充bottom half的个数。此时,不需要手工调用run_task_queue()(这原本就不合适),而只需调用mark_bh(IMMEDIATE_BH),让bottom half机制在合适的时候调度它。

tasklet

由上看出,task queue以bottom half为基础;而bottom half在v2.4.x中则以新引入的tasklet为实现基础。

之所以引入tasklet,最主要的考虑是为了更好的支持SMP,提高SMP多个CPU的利用率:不同的tasklet可以同时运行于不同的CPU上。在它的源码注释中还说明了几点特性,归结为一点,就是:同一个tasklet只会在一个CPU上运行。

struct tasklet_struct{ struct tasklet_struct *next; /* 队列指针 */ unsigned long state; /* tasklet的状态,按位操作,目前定义了两个位的含义: TASKLET_STATE_SCHED(第0位)或TASKLET_STATE_RUN(第1位) */ atomic_t count; /* 引用计数,通常用1表示disabled */ void (*func)(unsigned long); /* 函数指针 */ unsigned long data; /* func(data) */};

把上面的结构与tq_struct比较,可以看出,tasklet扩充了一点功能,主要是state属性,用于CPU间的同步。

tasklet的使用相当简单:

定义一个处理函数void my_tasklet_func(unsigned long); DECLARE_TASKLET(my_tasklet,my_tasklet_func,data); /* 定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联,相当于DECLARE_TASK_QUEUE() */ tasklet_schedule(&my_tasklet); /* 登记my_tasklet,允许系统在适当的时候进行调度运行,相当于queue_task(&my_task,&tq_immediate)和mark_bh(IMMEDIATE_BH) */

可见tasklet的使用比task queue更简单,而且,tasklet还能更好的支持SMP结构,因此,在新的2.4.x内核中,tasklet是建议的异步任务执行机制。除了以上提到的使用步骤外,tasklet机制还提供了另外一些调用接口:

DECLARE_TASKLET_DISABLED(name,function,data); /* 和DECLARE_TASKLET()类似,不过即使被调度到也不会马上运行,必须等到enable */
tasklet_enable(struct tasklet_struct *); /* tasklet使能 */
tasklet_disble(struct tasklet_struct *); /* 禁用tasklet,只要tasklet还没运行,则会推迟到它被enable */
tasklet_init(struct tasklet_struct *,void (*func)(unsigned long),unsigned long); /* 类似DECLARE_TASKLET() */
tasklet_kill(struct tasklet_struct *); /* 清除指定tasklet的可调度位,即不允许调度该tasklet,但不做tasklet本身的清除 */

前面提到过,在2.4.x内核中,bottom half是利用tasklet机制实现的,它表现在所有的bottom half动作都以一类tasklet的形式运行,这类tasklet与我们一般使用的tasklet不同。

在2.4.x中,系统定义了两个tasklet队列的向量表,每个向量对应一个CPU(向量表大小为系统能支持的CPU最大个数,SMP方式下目前2.4.2为32)组织成一个tasklet链表:

struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;

另外,对于32个bottom half,系统也定义了对应的32个tasklet结构:

struct tasklet_struct bh_task_vec[32];

在软中断子系统初始化时,这组tasklet的动作被初始化为bh_action(nr),而bh_action(nr)就会去调用bh_base[nr]的函数指针,从而与bottom half的语义挂钩。mark_bh(nr)被实现为调用tasklet_hi_schedule(bh_tasklet_vec+nr),在这个函数中,bh_tasklet_vec[nr]将被挂接在tasklet_hi_vec[cpu]链上(其中cpu为当前cpu编号,也就是说哪个cpu提出了bottom half的请求,则在哪个cpu上执行该请求),然后激发HI_SOFTIRQ软中断信号,从而在HI_SOFTIRQ

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top