您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > 其它相关文档 > Linux中断机制(2) - 北大深圳研究院
Linux中断机制(2)--软中断梁冰北大网络分布式实验室2004.11.151.软中断简介回忆前面的知识硬中断最后的处理do_IRQ()函数中,最后的一个处理是什么?do_softirq()!为什么要软中断?硬中断中是需要尽快响应和处理的,不能将太多时间放在中断事件的处理上,否则会丢失掉另外的相同类型的中断一些中断需要处理的工作不是那么急迫硬件中断打断CPU,软中断打断内核序列2.软中断分类Linux2.4.*系列有三种可延迟中断内核函数:软中断(softirq)小任务(tasklet)下半部分(bottomhalf)三者之间关系Tasklet用softirq实现,bottomhalf用tasklet实现3软中断,tasklet及下半部软中断非动态分配,需要内核编译同类软中断可以并发运行在几个CPU上Tasklet可以编程时动态分配,内核运行时,模块载入不同种类的taskelt可以并发在接个CPU上运行,同种的不行下半部分非动态分配,需要内核编译下半部分不能并发在几个CPU上运行注意任何可延迟函数都不能与其他的可延迟函数在同一个CPU上交错执行。3.1可延迟函数的一般操作初始化(Initialization)定义一个新的可延迟函数激活(Activation)标记一个可执行函数成为pending态激活可以在任何时候进行(中断处理中也可)屏蔽(Masking)有选择地屏蔽一个可延迟函数,使它即使被激活也不会被内核执行执行(Execution)执行一个可延迟函数和其他任何的可延迟函数给定CPU激活的可延迟函数一般在同一CPU上运行4可延迟函数---软中断详解在2.4.*内核中,定义了4种软中断低下标意味着高优先级,软中断函数从下标0开始执行4.1软中断主要数据结构Softirq_vec数组由softirq_action结构体组成的数组,默认内核只有前4项有用。structsoftirq_action{void(*action)(structsoftirq_action*);void*data;};4.1软中断主要数据结构Irq_stat是irq_cpustat_t数组,每一个CPU一个。其实在硬中断处理部分已经使用了其中的许多数据项了。typedefstruct{unsignedint__softirq_pending;unsignedint__local_irq_count;unsignedint__local_bh_count;unsignedint__syscall_count;structtask_struct*__ksoftirqd_task;/*waitqueueistoolarge*/unsignedint__nmi_count;/*archdependent*/}____cacheline_alignedirq_cpustat_t;4.1软中断数据结构Irq_cpustat_t__softirq_pending字段存放一组标志表示挂起的软中断__local_bh_count字段,禁止软中断的执行,为0则软中断被激活,为负数则被禁止__ksoftirq_task字段,存放ksoftirqd_CPUn内核线程的进程描述符,这种内核线程致力于可延迟函数的执行4.2软中断的相关调用初始化open_softirq()函数处理软中断的初始化,三个函数分别是软中断下标,要执行的软中断的激活__cpu_raise_softirq宏激活cup_raise_softirq函数激活,同时唤醒ksoftirq_CPUn内核线程4.2软中断的相关调用屏蔽__local_bh_count为0时打开软中断,为负(正?)数时禁止执行检查软中断的挂起是在内核代码的几个点上进行的。且挂起点的个数和位置随内核版本的变化而改变。以下以2.4.*内核为例:当local_bh_enable宏重新接活软中断时当do_IRQ完成时处理I/O的中断时当smp_apic_timer_interrupt函数完成了处理一个本地时钟中断时一个特定的ksoftirq_CPU内核线程被唤醒时当在网络接口卡上获取一个数据包时4.2软中断的相关调用关键代码:asmlinkagevoiddo_softirq(){intcpu=smp_processor_id();__u32pending;unsignedlongflags;__u32mask;if(in_interrupt())return;4.2软中断的相关调用local_irq_save(flags);pending=softirq_pending(cpu);if(pending){structsoftirq_action*h;mask=~pending;local_bh_disable();4.2软中断的相关调用restart:/*Resetthependingbitmaskbeforeenablingirqs*/softirq_pending(cpu)=0;local_irq_enable();h=softirq_vec;do{if(pending&1)h-action(h);h++;pending=1;}while(pending);4.2软中断的相关调用local_irq_disable();pending=softirq_pending(cpu);if(pending&mask){mask&=~pending;gotorestart;}__local_bh_enable();if(pending)wakeup_softirqd(cpu);}4.2软中断的相关调用几点注意及解释:•可延迟函数(软中断)必须在中断之外运行,否则就违背初衷了。•如果可延迟函数被禁止就不能执行了。•关中断修改数据结构,关软中断执行并开中断执行软中断函数•每一次在执行点上最多执行一次每一类的软中断函数,如果在开中断的时候被中断挂上去的函数,可以且最多可以执行一次•最后如果还有挂起的软中断没有执行,就唤醒ksoftirq_CPUn内核线程4.3软中断内核线程每个cpu都有一个自己的ksoftirq_CPUn内核线程(这里,n为CPU的逻辑号).每个ksoftirqd_CPUn内核线程都运行ksoftirqd()函数:ksoftirqd_task(cpu)=current;for(;;){if(!softirq_pending(cpu))schedule();__set_current_state(TASK_RUNNING);while(softirq_pending(cpu)){do_softirq();if(current-need_resched)schedule();}__set_current_state(TASK_INTERRUPTIBLE);}4.3软中断内核线程(续)软中断内核线程的必要性软中断函数可以自己重新激活自己,如网络软中断和tasklest软中断都可以如此,网卡上高流量可能激活大量软中断没有软中断内核线程,有两种极端的处理方法忽略do_softirq运行时新出现的软中断,就是在该函数开始执行时,确定哪些软中断是挂起的,然后一次执行完,但是之后就不再重新检查新的软中断,而是等到下次时钟中断后执行在do_softirq中不断检查软中断并执行,这样虽然满足大流量的软中断的执行,但是会使得用户进程长期得不到响应引入ksoftirqd可以在上述两种情况中作一个妥协和折衷5可延迟函数----tasklet(小任务)简述Tasklet是I/O驱动程序中实现可延迟函数的首选方法.Tasklet建立在两个叫做HI_SOFTIRQ和TASKLET_SOFTIRQ的软中断之上.实际上是一种软中断的应用.这两隔软中断没有太大差别,只是先执行前者后执行后者几个tasklet可以与同一个软中断相关联,即同一个软中断可以串行执行好多的tasklet5.1tasklet的数据结构tasklet_vec和tasklet_hi_vec二者分别对应两种软中断所执行的tasklet的数据结构,实际上二者都是一个指针数组,有NR_CPUS个元素,每个元素是tasklet_head的指针,tasklet_head含有指向tasklet_struct类型数据结构的指针(….晕了)structtasklet_struct{structtasklet_struct*next;unsignedlongstate;/*TASKLET_STATE_SKEEDorTASKLET_STATE_RUN*/atomic_tcount;void(*func)(unsignedlong);unsignedlongdata;};5.2tasklet调用步骤和原理先分配一个新的tasklet_struct数据结构,并由tasklet_init初始化它Tasklet_disable_nosync或者tasklet_disable函数可以选择性地禁止tasklet可以用tasklet_shedule或tasklet_hi_schedule来调度staticinlinevoidtasklet_schedule(structtasklet_struct*t){if(!test_and_set_bit(TASKLET_STATE_SCHED,&t-state))__tasklet_schedule(t);}5.2tasklet调用步骤和原理void__tasklet_schedule(structtasklet_struct*t){intcpu=smp_processor_id();unsignedlongflags;local_irq_save(flags);t-next=tasklet_vec[cpu].list;tasklet_vec[cpu].list=t;cpu_raise_softirq(cpu,TASKLET_SOFTIRQ);local_irq_restore(flags);}5.2tasklet调用步骤和原理分配一个新的tasklet_struct数据结构,调用tasklet_init初始化它调用tasklet_disable_nosync或tasklet_disable来选择性地禁止tasklet调用tasklet_schedule或tasklet_hi_shedule来激活函数在do_softirq函数中由tasklet_action和tasklet_hi_action执行具体的tasklet任务staticinlinevoidtasklet_schedule(structtasklet_struct*t){if(!test_and_set_bit(TASKLET_STATE_SCHED,&t-state))__tasklet_schedule(t);}5.2tasklet调用步骤和原理void__tasklet_schedule(structtasklet_struct*t){intcpu=smp_processor_id();unsignedlongflags;local_irq_save(flags);t-next=tasklet_vec[cpu].list;tasklet_vec[cpu].list=t;cpu_raise_softirq(cpu,TASKLET_SOFTIRQ);local_irq_restore(flags);}5.2tasklet调用步骤和原理inlinevoidcpu_raise_softirq(unsignedintcpu,unsignedintnr){__cpu_rai
本文标题:Linux中断机制(2) - 北大深圳研究院
链接地址:https://www.777doc.com/doc-4580873 .html