资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,#,下半部,下半部的任务主要是执行与中断相关的工作,这些工作没有被中断服务程序本身完成,.,主进程,中断,top,bottom,1.,与时间相关的工作,2.,与硬件相关的工作,3.,不希望被其他中断打断,其他工作,下半部下半部的任务主要是执行与中断相关的工作,这些工作没有被,1,历史,最初的机制:,BH,2.5,内核后被废止,任务队列,2.5,内核之后被工作队列替代,2.3,内核引入软中断(,softirq,)和,tasklet,32,个软中断,实际上只用到,6,个,tasklet,实现于软中断之上,2.5,内核引入工作队列,历史最初的机制:BH,2,为什么要把中断分为两部分,中断服务程序异步执行,可能会中断其他的重要代码,包括其他中断服务程序。因此,为了避免被中断的代码延迟太长的时间,中断服务程序需要尽快运行,.,希望限制中断服务程序所做的工作,因此处理中断的时间越短越好。,中断服务程序只作必须的工作,其他的工作推迟到以后处理。,2.6,内核的三种方法,:,softirqs,tasklet,和,work queue,为什么要把中断分为两部分中断服务程序异步执行,可能会中断其他,3,软中断,Softirqs,kernel/softirq.c,定义了一个,32,个元素的结构数组,/*,本结构代表了一个软中断项*,/,struct softirq_action,void(*sction)(struct softirq_action*);/*,带执行的函数*,/,void*data;/*,传给函数的指针*,/,固定,登记的,softirqs,最大数目不能动态改变,.,工作时允许中断,.,一个,softirq,不能抢占另一个。它只能被,中断服务程序,抢占,.,另一个,softirq,,甚至是同一个可运行于另一个,CPU,.,软中断Softirqskernel/softirq.c定义了,4,使用软中断,分配索引,注册处理程序,open_softirq(,索引号,处理程序,NULL),触发软中断,raise_softirq(,索引号,),softirq_pending(CPU),宏:返回指定,CPU,上未处理的软中断,软中断,优先级,Softirq,描述,HI_SOFTIRQ,0,优先级最高的,tasklets,TIMER_SOFTIRQ,1,定时器的下半部,NET_TX_SOFTIRQ,2,发送网络数据报,NET_RX_SOFTIRQ,3,接受网络数据报,SCSI_SOFTIRQ,4,SCSI,的下半部,TASKLET_SOFTIRQ,5,Tasklets,使用软中断分配索引软中断优先级Softirq 描述HI_SO,5,软中断的执行,中断处理程序在返回前标记它的软中断,使其在稍后执行,检查和执行待处理的软中断的时机:,-,从硬件中断代码返回;,-,在,ksoftirqd,内核线程中;,-,显式检查和处理软中断的代码中,使用软中断的情况:对时间要求最严格和最重要的下半部使用,-,网络和,SCSI,设备,-,内核定时器和,tasklet,软中断的执行中断处理程序在返回前标记它的软中断,使其在稍后执,6,Softirqs,的执行,u32 pending=softirq_pending(cpu);,if(pending),struct softirq_action*h=softirq_vec;,softirq_pending(cpu)=0;,do,if(pending&1),h-action(h);,h+;,pending=1;,while(pending);,1,1,1,0,31,Bitmap,Pending=100101,Pending=001010,Pending=010100,Pending=101000,Pending=010000,Pending=100000,1,0,0,1,0,1,Softirqs的执行 u32 pending=soft,7,Tasklet,的类型,Tasklet,优先级,Softirq,描述,HI_SOFTIRQ,0,优先级最高的,tasklets,TIMER_SOFTIRQ,1,定时器的下半部,NET_TX_SOFTIRQ,2,发送网络数据报,NET_RX_SOFTIRQ,3,接受网络数据报,SCSI_SOFTIRQ,4,SCSI,的下半部,TASKLET_SOFTIRQ,5,Tasklets,Tasklet 的类型Tasklet优先级Softirq 描,8,Tasklets,的结构,struct tasklet_struct,struct tasklet_struct*next;,unsigned long state;,/,见下,atomic_t count;,/*reference count,锁,*,/,void(*func)(unsigned long);/*tasklet,处理函数,*/,unsigned long data;,/*tasklet,处理函数的参数,*/,;,File:includeinterrupt.h,Enum,TASKLET_STATE_SCHED,/*Tasklet,已被调度,*/,TASKLET_STATE_RUN/*Tasklet,正在运行,(,只用于,SMP)*/,;,Tasklets的结构struct tasklet_stru,9,Tasklets,Taskle,t,s,实现于,softirq,之上,实际上也是,softirqs.,T,asklet,同时只运行于一个,CPU.,注,:,softirq,,甚至是同一个可运行于另一个,CPU,.,不同的,tasklets,可同时运行于不同的,CPU.,TaskletsTasklets 实现于softirq之上,,10,tasklet_schedule(),的调度过程,检查,tasklet,的状态是否为,TASKLET_STATE_SCHED,,如果是,则立即返回;,保存中断状态,禁止本地中断;,把需要调度的,tasklet,指定处理器的,tasklet_vec,或,tasklet_hi_vec,链表;,唤起,TASKLET_SOFTIRQ,或,HI_SORTIRQ,软中断,这样在下一次调用,do_softirq(),时会执行该,tasklet;,恢复中断到原状态并返回。,tasklet_schedule()的调度过程检查taskl,11,tasklet,处理过程,禁止中断,取当前处理器的,tasklet_vec,或,tasklet_hi_vec,链表;,将当前处理器的这两个链表清空;,允许响应中断;,循环遍历链表上的每一个待处理的,tasklet,;,如果是多处理器系统,则检查,TASKLET_STATE_RUN,标志判断这个,tasklet,是否在其他处理器上运行,如果在运行,则跳转掉下一个,tasklet,,否则置其状态为,TASKLET_STATE_RUN,;,检查,tasklet,是否被禁止,(count=0),,如果被禁止则跳到下一个,tasklet,;,执行,tasklet,程序;,执行完毕后,清除,TASKLET_STATE_RUN,标志;,重复下一个,tasklet,;直到所有的,tasklet,处理完。,tasklet处理过程禁止中断,取当前处理器的tasklet,12,使用,t,asklet,编写,tasklet,处理函数,void my_tasklet_fun(unsigned long data),声明,tasklet,静态,DECLARE_TASKLET,(my_tasklet,my_tasklet_func,data);,动态,tasklet_init(t,tasklet_handler,dev),调度,tasklet,tasklet_schedule,(&my_tasklet),登记,my_tasklet,然后允许系统在合适的时间调度它。,使用tasklet编写tasklet处理函数,13,软中断处理的时机,中断处理结束时,内核线程,ksoftirqd,在系统空闲时(每一个处理器有一个这样的线程),内核代码中其他调用,do_softirq,函数时,软中断处理的时机中断处理结束时,14,工作队列,Work,queue,将工作推迟给一个内核线程,work,总是运行于,进程上下文,.,如果推迟的工作需要睡眠,则使用,work queues,。否则使用,softirq,或,tasklets.,Work queues,适用于需要分配大量的内存,获得一个,信号量,,或者执行阻塞的,I/O,的情况,.,工作队列Work queue将工作推迟给一个内核线程 w,15,工作者线程,每个工作者线程一个,struct workqueue_struct,struct cpu_workqueue_struct cpu_wqNR_CPUS;,const char*name;/,工作者线程的名字,struct list_head list;/,指向其他工作者线程,;,工作者线程每个工作者线程一个,16,工作者线程,系统中每一个,CPU,有一个默认的工作者线程,events/n,,,n,是处理器编号。也可自己在创建新的工作者线程,工作者线程是一个内核线程,当有工作被插入到工作队列时,被唤醒,执行这些工作;没有工作时睡眠,工作者线程系统中每一个CPU有一个默认的工作者线程event,17,工作者线程的主要流程,循环执行:,线程将自己设置为睡眠态,等待有工作加入队列;,如果工作队列空,睡眠,否则线程执行,循环执行推迟的工作,伪代码见教材,88,页,工作者线程的主要流程循环执行:,18,工作的执行过程,循环执行:,链表非空时,取下一个工作,获取要执行的函数及参数,将工作从链表中摘除,将,pending,标志请,0,调用函数,重复执行,伪代码见教材,88-89,页,工作的执行过程循环执行:,19,工作者队列,每个,CPU,一个,struct cpu_workqueue_struct,spinlock_t lock;/*,互斥锁*,/,long remove_sequence;/*least-recently added(next to run)*/,long insert_sequence;/*next to add*/,struct list_head worklist;/*,工作列表*,/,wait_queue_head_t more_work;,wait_queue_head_t work_done;,struct workqueue_struct*wq;/*,相关的,workqueue_struct*/,task_t*thread;/*,相关的线程*,/,int run_depth;/*run_workqueue()recursion depth*/,;,工作者队列每个CPU一个,20,工作,struct work_struct,unsigned long pending;/*,工作是否等待处理*,/,struct list_head entry;/*,所有工作*,/,void(*func)(void*);/*,处理函数*,/,void*data;/*,处理函数的参数*,/,void*wq_data;/*,内部使用*,/,struct timer_list timer;/*,推迟的工作的定时器*,/;,工作struct work_struct,21,Work Queue,数据结构,worker thread,work_struct,cpu_workqueue_struct,1/CPU,workqueue_struct,1/thread type,work_struct,work_struct,1/deferrable function,Work Queue数据结构worker threadwor,22,使用,Work qu
展开阅读全文