Chinaunix首页 | 论坛 | 博客
  • 博客访问: 868981
  • 博文数量: 366
  • 博客积分: 10267
  • 博客等级: 上将
  • 技术积分: 4290
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:04
文章分类

全部博文(366)

文章存档

2012年(366)

分类: 嵌入式

2012-03-20 19:47:45

未完。。待续。。。


1.中断是内核不可缺少的一部分,但是中断处理程序本身存在一些局限性,

  a.中断方式以异步方式执行并且有可能会打断期待其他重要代码,甚至包括其它中断处理程序的执行,因此为了避免被打断的代码停止的时间过长,中断处理程序应该执行得越快越好。
  b.如果当前有一个中断处理程序在运行,在最好的情况下(如果设置了SA_INTERRUPT),与该中断同级的其它中断会被屏蔽,在最坏的情况下,当前处理器上所有其它中断都会被屏蔽,导致丢失中断,因此应当让他们执行得越快越好。
  c.由于中断处理程序往往需要对硬件进行操作,所以他们通常有很高的时限要求。
  d.中断处理程序不在进程上下文中运行,所以他们不能被阻塞。这限制了他们所做的事情。
 内核将中断分为上下两个部分,第一部分是中断处理程序,用来完成对硬件中断的即使响应,第二部分就是我们所说的下半部,完成余下的相对宽松的任务。
  上下部分的具体划分:
  a.如果一个任务对时间非常敏感,将其放在中断处理程序中运行
 b.如果一个任务和迎接爱你相关,放到中断处理程序
c.如果一个任务要保证不被其它中断特别的相同的中断打断,将其放到中断处理程序
d.余下任务放到下半部
  中断程序在运行当中,当前的中断线在所有处理器上都会被屏蔽,如果一个处理程序是SA_INTERRUPT类型,它执行的时候还会禁止所有本地中断,把本地中短线全局地屏蔽掉,缩短中断被屏蔽的时间对系统的响应能力和性能至关重要。下半部执行的关键在于他们运行的时候,允许响应中断。
2.下半部的实现方式
   2.6中内核提供了三种不同形式的下半部实现机制,软中断,tasklet和工作队列。还有一个特殊的延迟工具内核定时器。
   tasklet通过软中断形式实现。利用了一个软中断进入口。
3.软中断
  软中断在编程的时候金泰分配,有softirq_action结构表示,在中,
  struct softirq_action {
void (*action)(struct softirq_action *);
        void *data;
  }
  kernel/softirq.c中定义了一个包含32个该结构的数组。
  static struct softirq_action softirq_vec[32];
  由此可知最多有32个软中断。
  软中断处理程序原型如下:
  void softirq_handler(struct softirq_action *);
  一个软中断不会抢占另外一个软中断,唯一可抢占软中断的是中断处理程序,不过其它的软中断,或者相同类型的中断是可以在其它处理器上同时运行的。
  软中断的执行,触发;
  一个注册的软中断必须在被标记后才会执行,这被称作触发软中断,中断处理程序会返回前标记它的软中断,使其
  稍后被执行,于是在合适的时刻,该软中断就会运行,这些时刻包括如下这些:
   a.从一个硬件中断处理代码返回时
   b.zai ksoftirqd内核线程中
   c.在显示检查和执行待处理的软中断代码中,如网络子系统中。
   这些方法最终都是调用do_softirq()也就是,触发软中断一定要调用该函数。do_softirq()会循环遍历每一个调用他们的处理程序。
    
   软中断的使用
   软中断保留给系统中时间要求最严格最重要的下半部,目前只有两个子系统--网络和scsi--直接使用软中断,
   此外,内核定时器和tasklet都是简历在软中断上的,如果你想加入一个软中断,首先要考虑tasklet为什么不可以。
   编译期间可以通过中定义一个枚举类型来静态地声明软中断,内核用从0开始表示一种相对优先级,索引号小的软中断在索引大的软中断之前运行。
   已有的tasklet类型,
   HI_SOFTIRQ              //0,优先级高的tasklet
   TIMER_SOFTIRQ           //1,定时器的下半部
   NET_TX_SOFTIRQ          //2,发送网络数据包
   NET_RX_SOFTIRQ          //3,接收网络数据包
   SCSI_SOFTIRQ            //4,SCSI的下半部
   TASKLET_SOFTIRQ         //5,tasklet
  可以选择定义优先级在这几个中间,一般插在网络之后最后一项之前。
  软中断的注册,
  open_softirq(索引号,处理函数,相关数据);
  软中断处理程序执行时候,允许响应中断,但它自己不能睡眠,在一个处理程序运行的时候,当前处理器上的软中断被禁止。其它处理器仍可以执行别的软中断。实际上如果同一个软中断在它被执行的时候再次被触发,那么另外一个处理器可以同事运行其处理程序,因为进入接口只有一个,所以任何共享数据即使内部的全局变量都要严格保护。
  tasklet本身也是软中断,只不过同一个处理程序的多个实例不能在多个处理器上运行。
  raise_softirq()可以将一个软中断设置为挂起,让他在下次调用do_softirq时候运行。
  该函数在触发一个软中断之前要先禁止中断,触发后在回复回原来的状态,如果中断本来就被禁止了,可以使用raise_softirq_irqoff.
  
tasklet
  tasklet是利用软中断实现的一种下半部机制,在执行频率很高和连续性要求很高的情况下使用软中断,否则请使用tasklet。
  tasklet本身也是软中断,tasklet由tasklet_struct结构表示,每个结构体代表一个tasklet,在中定义: 
  struct tasklet_struct{
struct tasklet_struct *next;    //下一个tasklet
        unsigned long state;            //状态,0,TASKLET_STATE_SCHED,TASKLET_STATE_RUN.
        atomic_t      count;            //引用计数,如果不为0则tasklet被禁止,不允许执行,如果为0,激活
        void (*func)(unsigned long);    //tasklet处理函数
        unsigned long data;             //处理函数参数
  }
 结构tasklet_vec代表普通tasklet,tasklet_hi_vec代表优先级高的tasklet,tasklet由tasklet_schedule()和
 tasklet_hi_schedule()函数进行调度,他们接受一个指向tasklet_stuct结构的指针作为参数,看一下
 tasklet_schedule()细节,
 1.检查tasklet转台是否为tasklet_state_sched,如果是说明tasklet已经被调度过了,函数立即返回,此时可能
   该tasklet被调度但还没有被执行。
 2.保存中断状态,禁止本地中断。保证数据不会弄乱。
 3.把要调度的tasklet加到对应的tasklet_VEC或者tasklet_hi_vec中去
 4.唤起TASKLET_SOFTIRQ或者TASKLET_IRQ软中断,下次就会执行do_softirq调用到
 5.恢复中断
 其中tasklet_action()和tasklet_hi_action()是tasklet处理的核心:
 1.禁止中断,
 2.将当前处理器上的该链表清空
 3.允许响应中断
 4.循环遍历获得链表上的每一个待处理的tasklet
 5.多处理器通过检测tasklet_state_run来判断是否在其它处理器上运行,如果运行那么现在该处理器不运行,同一  时间相同的tasklet只执行一个
 6.如果当前的tasklet没有执行,将其状态标志位tasklet_state_run这样别的处理器就不会执行他
 7.检查count是否为0,如果被禁止,跳到下一个
 8.执行tasklet 
 9.清除tasklet的state状态
 10.重复执行下一个tasklet,直到没有剩余的等待处理的tasklet。
 所有的tasklet都是通过HI_SOFTIRQ和TASKLET_SOFTIRQ这两个软中断实现,在他们之上又延伸了一层。
 tasklet的使用:
 1.声明你的tasklet

   可以静态也可以动态


-----参考

阅读(501) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~