yd2763132的个人空间 https://www.eechina.com/space-uid-36266.html [收藏] [复制] [RSS]

博客

中断和定时器

已有 1014 次阅读2011-5-12 20:10 |个人分类:linux|

    为了提高吞吐量势必要求中断程序尽可能短小,所以将中断处理程序分解为两个部分: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----)


路过

鸡蛋

鲜花

握手

雷人

发表评论 评论 (1 个评论)

回复 liyunbing84 2011-5-12 23:08
我的GG,这不是LINUX中的一段吗?写也要写明白点。

facelist

您需要登录后才可以评论 登录 | 立即注册

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
返回顶部