Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14863
  • 博文数量: 5
  • 博客积分: 265
  • 博客等级: 二等列兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-14 20:10
文章分类
文章存档

2009年(3)

2008年(2)

我的朋友
最近访客

分类: LINUX

2009-10-06 11:44:27

提出软中断的原因: 中断嵌套。如果允许中断服务程序再次被中断(set_irq(n,xx), 其中xx结构置为(action,SA_INTERRUPT),代表actio可以被中断);或者不允许全程关中断,都会过犹不及。

 

因此,产生了bottom half机制。

 

全局数组bh_base32个元素,当需要执行一个bh函数时,通过mark_bhunsigned long bh_active中的某一位设成1,如果bh_mask的相应位也是1,即允许中断调用,则每次在do_IRQ执行完之后,会调用do_bottom_half执行bh函数。

 

softirq_init对内核的软中断初始化:

{

       for(i=0;i<32;++i)

       tasklet_init(bh_task_vec+i,bh_acton,i);

 

open_softirq(TASKLET_SOFTIRQ,tasklet_action,NULL);

       open_softirq(HI_SOFTIRQ,tasklet_hi_action,NULL);

}

bh_task_vec是全局tasklet_struct结构数组

 

tasklet_init(t,f)

{

       t->func = f;

}

 

对于其他软中断的初始化,则是:

open_softirq(nr,action)

{

       softirq_vec[nr].action = action;

}

softirq_vec也是一个32个元素的数组,同时,还有一个以CPU为编号的tasklet_hi_vec[],里面有一个tasklet_struct队列的头指针,即每个CPU有一个tasklet_struct结构数组

 

回到tasklet机制,taskletfunction指针,指向bh_action,但并未挂载实际的处理程序。具体的bh函数是通过init_bh设置的,如后面要讲的时钟中断,

Sched.c:

Init_bh(TIMER_BH,timer_bh);

{

       bh_base[nr]=xx_bh;

}

其中,bh_base即是会被执行的函数指针数组。

 

当需要执行一个特定bh函数时,通过

mark_bh(nr)àtasklet_hi_schedule(bh_task_vec+nr)

{

tasklet_hi_vec[cpu].list = bh_task_vec+nr;

cpu_raise_softirq

}àcpu_raise_softirq(cpu,nr)

{

       softirq_active(cpu)|=1<

}

将处理函数挂接到tasklet_hi_vec结构上,同时将该cpu对应软中断标志位置1

到目前为止,软件消息发送过程结束,接下来看内核什么时候对该消息进行处理。

 

 

软中断,非tasklet执行方式:

内核每当在do_IRQ执行完毕一个中断服务程序后,进入软中断:

If(softirq_activecpu)&softirq_mask(cpu))

       do_softirq();

 

do_softirq()

{

 active = softirq_active(cpu)&mask

 if(active)

       {

         do{

              if(active&1)

                     h->action(h);

              h++;

              active>>1;

         }while(active)

       }

}

在上述代码中,内核检测CPUactive标志,看哪些nr位被置1,从而执行相应的action;在这里,h指针,和active最低位,是一一对应的,即他们会同时变化。

do_softirq()àsoftirq_vec.action[nr]àbh_action(nr)-àbh_base[nr]()

 

 

时钟中断:

初始化在start_kernel中,位于调度的初始化之后,因为一旦时钟中断开始生效,则马上开始调度。

sched_init(); time_init();

系统时钟,主要是两个全局变量,一个是struct timeval xtime,代表从历史某一时刻开始的时间绝对值,一般是1970年开始;

另外一个是开机以来的时钟中断的次数,unsigned ling jiffies,而中断的间隔时间,称为一个tick,取决于系统中一个常数,tick一般是20ms

 

中断初始化time_init函数的主要作用是,将0号向量注册为时间中断irqaction

set_irq(0,&irq0);

 

irq0是一个irqaction结构

static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0 ,”timer”, NULL, NULL};

 

ps: time.cirq0被声明为static,说明该变量只能在timer.c中被使用。

 

第二个参数被置SA_INTERRUPT,所以该中断不能被嵌套,中断服务器程序为timer_interrupt-àdo_timer_interrupt(irq,NULL,regs)àdo_timer

{

       (*(unsigned long*)&jiffies)++;

       mark_bh(TIMER_BH);

       mark_bh(TQUEUE_BH);

 

}

 

解释一下,第一句为啥不用jiffies++  ,这样写是因为,编译器会把这种写法翻译成一条原子指令(对内存单元的INC指令)

 

后面的两个mark_bh,是分别“激活”TIMER_BHTQUEUE_BH,所谓激活的意思,就是将bh_task_vec[TIMER_BH]挂载到tasklet_hi_vec队列中,同时也置该CPU对应软中断位1mark_bh(nr)àtasklet_hi_schedule(bh_task_vec+nr)

{

tasklet_hi_vec[cpu].list = bh_task_vec+nr;

cpu_raise_softirq

}àcpu_raise_softirq(cpu,nr)

{

       softirq_active(cpu)|=1<

}

 

中断返回之前,执行与TIMER_BH对应的timer_bh函数,这个是在sched_init中初始化的:

init_bh(TIMER_BH,timer_bh);

 

timer_bh,就是时间中断的软中断部分要完成的函数实现,也是时钟中断最重要的函数。前面的硬中断,do_timer中完成的功能很少,并且要在关中断的情况下执行,而timer_bh是大多数操作实现的地方。

timer_bh完成的功能,主要是,update_timesà更新wall timer,以及计算cpu负荷的统计信息cal_load

以及,最终的run_timer_list就是定时器执行的函数操作,比如用户定义的到点操作函数,都是在这个函数里完成的。timer_list的结构如下:

struct timer_list{

unsigned long expire;

void (*function)(unsigned long);

}

阅读(1051) | 评论(0) | 转发(0) |
0

上一篇:文件操作相关

下一篇:中断概述

给主人留下些什么吧!~~