引用网址:
http://edu.codepub.com/2010/0209/20378.phplinux的中断线程化实现
http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html
Linux内核中断内幕
中断线程化介绍(InterruptThreads)
在嵌入式领域,业界对Linux实时性的呼声越来越高,对中断进行改造势在必行。在Linux中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍有实时性保证。
目前较新的Linux2.6.17还不支持中断线程化。但由IngoMolnar设计并实现的实时补丁,实现了中断线程化。最新的下载地址为:
http://people.redhat.com/~mingo/realtime-preempt/patch-2.6.17-rt9
下面将对中断线程化进行简要分析。
在初始化阶段,中断线程化的中断初始化与常规中断初始化大体上相同,在start_kernel()函数中都调用了trap_init()和init_IRQ()两个函数来初始化irq_desc_t结构体,不同点主要体现在内核初始化创建init线程时,中断线程化的中断在init()函数中还将调用init_hardirqs(kernel/irq/manage.c(已经打过上文提到的补丁)),来为每一个IRQ创建一个内核线程,最高实时优先级为50,依次类推直到25,因此任何IRQ线程的最低实时优先级为25。
void__initinit_hardirqs(void)
{
……
for(i=0;i<NR_IRQS;i++){
irq_desc_t*desc=irq_desc+i;
if(desc->action&&!(desc->status&IRQ_NODELAY))
desc->thread=kthread_create(do_irqd,desc,"IRQ%d",irq);
……
}
}
staticintdo_irqd(void*__desc)
{
……
/*
*Scaleirqthreadprioritiesfromprio50toprio25
*/
param.sched_priority=curr_irq_prio;
if(param.sched_priority>25)
curr_irq_prio=param.sched_priority-1;
……
}
|
如果某个中断号状态位中的IRQ_NODELAY被置位,那么该中断不能被线程化。
在中断处理阶段,两者之间的异同点主要体现在:两者相同的部分是当发生中断时,CPU将调用do_IRQ()函数来处理相应的中断,do_IRQ()在做了必要的相关处理之后调用__do_IRQ()。两者最大的不同点体现在__do_IRQ()函数中,在该函数中,将判断该中断是否已经被线程化(如果中断描述符的状态字段不包含IRQ_NODELAY标志,则说明该中断被线程化了),对于没有线程化的中断,将直接调用handle_IRQ_event()函数来处理。
fastcallnotraceunsignedint__do_IRQ(unsignedintirq,structpt_regs*regs)
{
……
if(redirect_hardirq(desc))
gotoout_no_end;
……
action_ret=handle_IRQ_event(irq,regs,action);
……
}
intredirect_hardirq(structirq_desc*desc)
{
……
if(!hardirq_preemption||(desc->status&IRQ_NODELAY)||!desc->thread)
return0;
……
if(desc->thread&&desc->thread->state!=TASK_RUNNING)
wake_up_process(desc->thread);
……
}
|
对于已经线程化的情况,调用wake_up_process()函数唤醒中断处理线程,并开始运行,内核线程将调用do_hardirq()来处理相应的中断,该函数将判断是否有中断需要被处理,如果有就调用handle_IRQ_event()来处理。handle_IRQ_event()将直接调用相应的中断处理函数来完成中断处理。
不难看出,不管是线程化还是非线程化的中断,最终都会执行handle_IRQ_event()函数来调用相应的中断处理函数,只是线程化的中断处理函数是在内核线程中执行的。
并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当被线程化。如果某个中断需要被实时处理,它可以像时钟中断那样,用SA_NODELAY标志来声明自己非线程化,例如:
staticstructirqactionirq0={
timer_interrupt,SA_INTERRUPT|SA_NODELAY,CPU_MASK_NONE,"timer",NULL,NULL
};
|
其中,SA_NODELAY到IRQ_NODELAY之间的转换,是在setup_irq()函数中完成的。
linux的中断线程化实现
2.6.25.8内核实现了中断线程化,内核为每一个中断向量建立了一个中断线程,具体就是在结构irq_desc中增加了一个task_struct来代表这个线程:
structirq_desc{
irq_flow_handler_thandle_irq;
structirq_chip*chip;
structmsi_desc*msi_desc;
void*handler_data;
void*chip_data;
structirqaction*action;/*IRQactionlist*/
unsignedintstatus;/*IRQstatus*/
unsignedintdepth;/*nestedirqdisables*/
unsignedintwake_depth;/*nestedwakeenables*/
unsignedintirq_count;/*FordetectingbrokenIRQs*/
unsignedintirqs_unhandled;
unsignedlonglast_unhandled;/*Agingtimerforunhandledcount*/
structtask_struct*thread;//中断线程
wait_queue_head_twait_for_handler;
cycles_ttimestamp;
raw_spinlock_tlock;
constchar*name;
}
在中断产生的时候,还是和往常一样进入do_IRQ,这个函数几乎没有什么变化,在do_IRQ中调用了irq_desc的handle_irq函数,这个handle_irq是向量相关的,比如有边缘触发等等,这个方式涉及到了硬件规程,故不深入讨论,实际上,每个总线邦定到一个中断向量,而总线的中断方式是总线相关的所以中断向量的方式也就和硬件相关了,这里就以Leveltype为例来说明,Leveltype的handle_irq是handle_level_irq:
voidhandle_level_irq(unsignedintirq,structirq_desc*desc)
{
unsignedintcpu=smp_processor_id();
structirqaction*action;
irqreturn_taction_ret;
spin_lock(&desc->lock);
mask_ack_irq(desc,irq);//屏蔽该中断,以防重入
if(unlikely(desc->status&IRQ_INPROGRESS))//如果正在处理则返回
gotoout_unlock;
desc->status&=~(IRQ_REPLAY|IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;
action=desc->action;
if(unlikely(!action||(desc->status&IRQ_DISABLED)))//禁用则返回
gotoout_unlock;
desc->status|=IRQ_INPROGRESS;//标记为正在处理
if(redirect_hardirq(desc))//检测是否为线程化中断,若是则唤醒中断线程
gotoout_unlock;
spin_unlock(&desc->lock);
action_ret=handle_IRQ_event(irq,action);//非线程化中断,处理之
if(!noirqdebug)
note_interrupt(irq,desc,action_ret);
spin_lock(&desc->lock);
desc->status&=~IRQ_INPROGRESS;
if(!(desc->status&IRQ_DISABLED)&&desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}
我们看看每个中断向量的中断线程是怎么初始化的,初始化的细节可以带给我们一大部分必要的信息,在实际开发中一定注意这一点,一个好的初始化带来的是将来操作的方便与清晰:
void__initinit_hardirqs(void)
{
inti;
ok_to_create_irq_threads=1;
for(i=0;i<NR_IRQS;i++){//对于每一个中断向量建立一个中断线程
irq_desc_t*desc=irq_desc+i;
if(desc->action&&!(desc->status&IRQ_NODELAY))//有IRQ_NODELAY标志的中断不允许线程化
start_irq_thread(i,desc);//实际建立线程
}
}
staticintstart_irq_thread(intirq,structirq_desc*desc)
{
if(desc->thread||!ok_to_create_irq_threads)
return0;
desc->thread=kthread_create(do_irqd,desc,"IRQ-%d",irq);//建立一个内核线程,赋值给desc->thread。
if(!desc->thread){
return-ENOMEM;
}
smp_mb();
wake_up_process(desc->thread);//一切就绪之前即desc->thread被赋值之前可能已经有了中断,故唤醒该中断线程处理之。
return0;
}
staticintdo_irqd(void*__desc)
{
structsched_paramparam={0,};
structirq_desc*desc=__desc;
current->flags|=PF_NOFREEZE|PF_HARDIRQ;
param.sched_priority=MAX_USER_RT_PRIO/2;
sys_sched_setscheduler(current->pid,SCHED_FIFO,¶m);//设置实时优先级
while(!kthread_should_stop()){
local_irq_disable_nort();
do{
set_current_state(TASK_INTERRUPTIBLE);//一定设置这个标志,否则很少有进程可以抢占中断线程,毕竟它是实时线程,如果不设这个标志,即使下面它自己schedule了,那么很大的可能性还是会选中它的
do_hardirq(desc);//处理中断请求
margin-top: 0pt; margin-bottom: 0pt; l
分享到:
相关推荐
linux的中断线程化实现[借鉴].pdf
---------------------------------------------------Linux 中的各种栈:进程栈 线程栈 内核栈 中断栈
linux软中断,软中断是linux系统原“底半处理”的升级,在原有的基础上发展的新的处理方式,以适应多cpu 、多线程的软中断处理。
这是一个spi模块的程序,对于深入了解linux驱动编程非常有益。其中涉及了中断、调度、多线程编程等
Linux Virtual Server (LVS)之ksoftirqd进程耗尽单核100%si处理软中断导致性能瓶颈; Linux 线程库性能测试与分析; 网卡软中断不能分发到CPU多核 问题的说明; Linux的实时性能测试.pdf 多核处理器上,怎样将...
3.2中断描述符表的初始化 3.3异常处理 3.4 中断处理 3.5中断的后半部分处理机制 第四章 进程描述 4.1 进程和程序(Process and Program) 4.2 Linux中的进程概述 4.3 task_struct结构描述 4.4 task_struct结构在内存...
在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断 处理程序,等到所有挂起的...中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以。
13.中断和中断处理 14.设备驱动程序 15.文件系统 16.网络系统 17.系统内核机制 18.linux内核编程模块 19.有关进程通信的编程 20.高级线程编程 21.linux网络编程 22.linux IO编程 23.linux系统管理员安全 24.linux...
在心电监护系统中引入嵌入式Linux操作系统,将操作系统作为嵌入式系统软硬件协同开发的核心,合理管理和调度资源,为智能化应用提供软件应用平台,针对通用Linux在实时性能方面的不足,提出以中断线程化、改进实时...
第13章 中断和中断处理 第14章 设备驱动程序 第15章 文件系统 第16章 网络系统 第17章 系统内核机制 第四篇 Linux系统高级编程 第18章 Linux内核模块编程 第19章 有关进程通信的编程 第20章 高级线程编程 第21章 ...
然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...
针对Linux2.6内核,分析了其在进程调度、中断处理、内核锁机制...开发了专用的测试模块,并使用Linux内核保留的中断号测试中断线程化效果。该方案能很好地解决中断对实时任务的干扰问题,对提高Linux实时性能有较好效果。
5.2 中断描述符表的初始化 114 5.2.1 IDT表项的设置 114 5.2.2 对陷阱门和系统门的初始化 115 5.2.3 中断门的设置 116 5.3 中断处理 116 5.3.1 中断和异常的硬件处理 116 5.3.2 中断请求队列的建立 117 5.3.3 中断...
然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...
然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...
它们涵盖的范围,包括从对中断服务例程的特殊使用和用户线程对硬件访问,到出现于有些ROTS中的半规范化驱动程序模型。它对于移植RTOS 代码到规范化模式的Linux设备启动程序具有启发性,并且介绍了一些方法。特别地,...
第二部分:深入分析进程创建的写时拷贝技术、以及Linux的线程究竟是怎么回事(为什么称为轻量级进程),此部分也会搞清楚进程0、进程1和托孤,以及睡眠时的等待队列;第三部分:搞清楚Linux进程调度算法,不同的调度...
然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...
然后对Linux内核的3大核心模块——内存管理、进程管理、中断和异常处理进行了深入的分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中常见的同步机制,使读者掌握每处理器变量和RCU...
对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。 切换的性能消耗: 1、线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存...