现在的位置: 首页 > 综合 > 正文

中断和定时器

2013年10月04日 ⁄ 综合 ⁄ 共 2845字 ⁄ 字号 评论关闭

为了提高吞吐量势必要求中断程序尽可能短小,所以将中断处理程序分解为两个部分:top halfbottom half.顶半部只需完成底半部的调度即可,底半部则完成中断函数大部分。


     Tasklet ,工作队列,软中断为底半部调度机制。他们的使用方式都是如下:

 先定义Tasklet  工作队列 软中断和相关的处理函数,再初始化相关结构体,最后在顶半部开启调度函数即可。

     Tasklet 软中断的实质都是软中断:即是硬件中断函数对内核的中断,故而运行于中断上下文;而工作队列本质是使用守护线程 运行于进程上下文;所以前者服务函数中不能有睡眠,而后者可以。

struct tasklet_struct

 

       struct tasklet_struct *next;//next tasklet    

       unsigned long state;//tasklets state    TASKLET_STATE_SCHED被调度  TASKLET_STATE_RUN已运行 

       atomic_t count;//uses counter  不为0时表示被禁止,为0时不为激活 

       void (*func)(unsigned long);  //bottom half FUNC   

        unsigned long data;// func”S parament 

};     

      tasklet_schedule函数为如下:检查state变量是否为TASKLET_STATE_SCHED,是则保存中断状态屏蔽本地中断源,把需要调度的tasklet加到每个处理器的tasklist_vec链表表头上去,唤醒tasklet_softirq软中断这样下一次do_softirq()调用时就会执行该tasklet,恢复中断状态回。

 

       Workqueue机制就是为了简化内核线程的创建,内核开始为用户分配一个workqueue对象,并且将其链到一个全局的workqueue队列中,然后Linux根据当前CPU的情况为workqueue对象分配与CPU个数相同的cpu_workqueue_struct对象,每个cpu_workqueue_struct对象都会存在一条任务队列(work_struct链成的链表)Linux为每个cpu_workqueue_struct对象分配一个内核thread(daemon守护进程)去处理每个任务队列中的任务,内核线程工作比较简单,就是不断的扫描对应cpu_workqueue_struct中的任务队列,从中获取一个有效任务,然后执行该任务。所以如果任务队列为空,那么内核daemon就在cpu_workqueue_struct中的等待队列上睡眠,直到有人唤醒daemon去处理任务队列。

 

    在Workqueue机制中,提供了一个系统默认的workqueue队列——keventd_wq,这个队列是Linux系统在初始化的时候就创建的。用户可以直接初始化一个work_struct对象,然后在该队列中进行调度,使用更加方便(中断只是定义一个工作节点work_struct对象和他的处理函数后加入到 keventd_wq结构中的任务队列中,使用schedule_work唤醒daemon去处理任务队列).



struct workqueue_struct {  

         struct cpu_workqueue_struct *cpu_wq; //每个CPU的工作队列结构

         const char *name;  

         struct list_head list; /* 工作队列所有的线程链表,根据系统CPU个数创建线程数量.创造一个线程时为空

}; 

工作节点结构是对任务的抽象                                        

struct work_struct {  

       unsigned long pending; //等待

       struct list_head entry; /* 任务挂载链表*/

       void (*func)(void *);/* 处理函数 */ 

       void *data; /* 任务处理的数据*/

       void *wq_data;/* work的属主cpu_workqueue_struct*/

       struct timer_list timer;/* 任务延时处理定时器 */

};

struct cpu_workqueue_struct {  

          spinlock_t lock;  

          long remove_sequence; // 下一个要执行的节点序号

          long insert_sequence; // 下一个要插入节点的序号

          struct list_head worklist; // 工作节点链表

          wait_queue_head_t more_work; // 要进行处理的等待队列

          wait_queue_head_t work_done; // 处理完的等待队列

          //以上两个等待队列用于daemon进程,当没有任务时则链接到 more_work睡眠等待,处理完后链接 

      到work_done只等到新的任务节点加入时重新链接到more_work睡眠等待

 

          struct workqueue_struct *wq; // 工作队列节点

          struct task_struct *thread; // 进程指针

          int run_depth; /* Detect run_workqueue() recursion depth */

} ____cacheline_aligned;

 

 

 

图中 workqueue_struct ->cpu_wq=&cpu_workqueue_struct   

workqueue_struct -> listdaemon0--2链接而成

cpu_workqueue_struct -> wq=& workqueue_struct表示属于该工作队列

cpu_workqueue_struct ->  thread=daemon0--2

work_struct -> wq_data=& cpu_workqueue_struct表示属于该cpu处理

第一个工作节点有 work_struct.entry.pre= &cpu_workqueue_struct .worklist.next

最后一个工作节点有 work_struct.entry.next=&cpu_workqueue_struct .worklist.pre

 

其余的工作节点 work_struct.entry均互相链接成一个任务链表 ----work-work-work----)

 

抱歉!评论已关闭.