“小王,醒醒,开端上课了,今日我们开端讲中止,这可是高档东西,错失不补哈”我用力推着睡梦中的小王。
“嗯?爱情好啊,快点,快点”小王一听有新东西讲,像打了鸡血似的振奋,连我都置疑起她是不是性情中喜新厌旧。
不论那么多了,我讲我的,她厌她的…
啥叫中止?就是指cpu在履行过程中,呈现了某些突发事件时CPU有必要暂停履行当时的程序,转去处理突发事件,处理完毕后CPU有回来原程序被中止的方位并持续履行。
中止的分法不明白,分类就不同,向什么内外部中止,可/不行屏蔽中止…等等杂乱无章一大堆,我这儿要阐明的一点是依照中止进口跳转办法的不同,可分为向量中止和非向量中止。选用向量中止的CPU一般为不同的中止分配不同的中止号,当检测到某中止号的中止到来后,就主动跳转到与该中止号对应的地址履行。不同的中止号有不同的中止地址(即进口)。而非向量中止的多个中止同享一个进口地址。进入后依据软件判别中止标志来辨认详细是哪个中止。也就是说,向量中止是由硬件供给中止服务程序进口地址,非向量中止由软件供给中止服务程序进口地址。
我们在后边会提到一个时钟定时器,它也是经过中止来完结的。它的原理很简单,嵌入式微处理器它接入一个时钟输入,当时钟脉冲到来时,就将现在的计数器值加1并和预先设置的计数值比较,若持平,证明计数周期满,产生定时器中止并复位现在计数器值。
Linux中止处理架构
设备的中止会打断内核中进程的正常调度和运转,会影响体系的功用。为了在中止履行时间尽可能短和中止处理需完结很多作业之间找到一个平衡点,Linux将中止处理程序分解成两个半部:顶半部和底半部。其间顶半部尽可能完结尽可能少的比较紧迫的功用。而底半部简直做了中止处理程序一切的作业,并且能够被新的中止打断。
在linux设备驱动中,供给了一系列函数来协助设备完结中止的相关操作:
1)设备请求中止
int request_irq(unsigned int irq, //irq是要请求的中止号
void (*handler)(int irq, void *dev_id, struct pt_regs * *regs),//回调函数,中止产生时,体系会调用该函数,
unsigned long irqflags,
const char *devname,
void *dev_id);
其间irqflags是中止处理的特点,若设置为SA_INTERRUPT,则表明中止处理程序是快速处理程序,它被调用时屏蔽一切中止。若设置为SA_SHIRQ,则表明多个设备同享中止,dev_id在中止同享时会用到,一般设置为这个设备的设备结构体或许NULL.
该函数回来0表明成功,回来-INVAL表明中止号无效或处理函数指针为NULL,回来EBUSY表明中止现已被占用且不能同享。
2)开释中止
free_irq(unsigned int irq, void *dev_id);
3)使能和屏蔽中止
void disable_irq(int irq); //这个会当即回来
void disable_irq_nosync(int irq);//等候现在的中止处理完结再回来。
void enable_irq(int irq);
上述三个函数作用于可编程中止处理器,因而对体系内一切的CPU都收效。
void local_irq_save(unsigned long flags);//会将现在的中止状况保留在flags中
void local_irq_disable(void);//直接中止
这两个将屏蔽本CPU内的一切中止。对应的上边两个中止的办法如下
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
我们两头说了Linux体系中中止是分为顶半部和底半部的,那么在体系完结方面是详细怎样完结的呢,这主要有tasklet,作业行列,软中止:
1)tasklet:运用比较简单,如下:
void my_tasklet_function(unsigned long); //界说一个处理函数
DECLARE_TASKLET(my_tasklet, my_tasklet_function, data); //界说了一个名叫my_tasklet的tasklet并将其与处理函数绑定,而传入参数为data
在需求调度tasklet的时分引证一个tasklet_schedule()函数就能使体系在恰当的时分进行调度运转:tasklet_schedule(&my_tasklet);
2)作业行列:运用办法和tasklet类似,如下:
struct work_struct my_wq; //界说一个作业行列
void my_wq_func(unsigned long); //界说一个处理函数
经过INIT_WORK()能够初始化这个作业行列并将作业行列与处理函数绑定,如下:
INIT_WORK(&my_wq, (void (*)(void *))my_wq_func, NULL); //初始化作业行列并将其与处理函数绑定
相同,运用schedule_work(&my_irq);来在体系在恰当的时分需求调度时运用运转。
3)软中止:运用软件方法模仿硬件中止的概念,完结微观上的异步履行作用,tasklet也是依据软中止完结的。
在Linux内核中,用softirq_action结构体表征一个软中止,这个结构体中包括软中止处理函数指针和传递给函数的参数,运用open_softirq()能够注册软中止对应的处理函数,而raise_softirq()函数能够触发一个中止。
软中止和tasklet依然运转与中止上下文,而作业行列则运转于进程上下文。因而,软中止和tasklet的处理函数不能休眠,但作业行列是能够的。
local_bh_disable()和local_bh_enable()是内核用于制止和使能软中止和tasklet底半部机制的函数。
下边我们再来说说有关中止同享的相关点:中止同享便是多个设备同享一根硬件中止线的状况。Linux2.6内核支撑中止同享,运用办法如下:
*同享中止的多个设备在请求中止时都应该运用SA_SHIRQ标志,并且一个设备以SA_SHIRQ请求某中止成功的条件是之前该中止的一切设备也都以SA_SHIRQ标志请求该终端
*虽然内核模块可拜访的大局地址都能够作为request_irq(….,void *dev_id)的最终一个参数dev_id,可是设备结构体指针是可传入的最佳参数。
*在中止带来时,一切同享此中止的中止处理程序都会被履行,在中止处理程序顶半部中,应敏捷依据硬件寄存器中的信息对比传入的dev_id参数判别是否是被设备的中止,假如不是,应敏捷回来。
结语:在这次解说中说了三种Linux体系中中止的顶/底半部机制和中止同享的先关内容,但碍于页面空间的原因,没有给出比如,我在下次博客中会专门来对每个点给出典型的模版.