Linux软中断的实现Word格式.docx

上传人:b****0 文档编号:12934638 上传时间:2022-09-30 格式:DOCX 页数:4 大小:15.13KB
下载 相关 举报
Linux软中断的实现Word格式.docx_第1页
第1页 / 共4页
Linux软中断的实现Word格式.docx_第2页
第2页 / 共4页
Linux软中断的实现Word格式.docx_第3页
第3页 / 共4页
Linux软中断的实现Word格式.docx_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux软中断的实现Word格式.docx

《Linux软中断的实现Word格式.docx》由会员分享,可在线阅读,更多相关《Linux软中断的实现Word格式.docx(4页珍藏版)》请在冰豆网上搜索。

Linux软中断的实现Word格式.docx

复制代码NR_SOFTIRQS是最大软中断向量数,内核支持的所有软中断如下:

enum{HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,TASKLET_SOFTIRQ,SCHED_SOFTIRQ,HRTIMER_SOFTIRQ,RCU_SOFTIRQ,/*PreferableRCUshouldalwaysbethelastsoftirq*/NR_SOFTIRQS};

复制代码好像后为为RPS新增了一个,不过这我的内核版本偏低。

1.2激活当需要调用软中断时,需要调用raise_softirq函数激活软中断,这里使用术语“激活”而非“调用”,是因为在很多情况下不能直接调用软中断。

所以只能快速地将其标志为“可执行”,等待未来某一时刻调用。

为什么“在很多情况下不能直接调用软中断”?

试想一下下半部引入的理念,就是为了让上半部更快地执行。

如果在中断程序代码中直接调用软中断函数,那么就失去了上半部与下半部的区别,也就是失去了其存在的意义。

内核使用一个名为__softirq_pending的位图来描述软中断,每一个位对应一个软中断,位图包含在结构irq_stat中:

typedefstruct{unsignedint__softirq_pending;

……}____cacheline_alignedirq_cpustat_t;

DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t,irq_stat);

复制代码宏or_softirq_pending用于设置相应的位(位或操作):

#defineor_softirq_pending(x)percpu_or(irq_stat.__softirq_pending,(x))复制代码local_softirq_pending用于取得整个位图(而非某一位):

#definelocal_softirq_pending()percpu_read(irq_stat.__softirq_pending)复制代码宏__raise_softirq_irqoff是or_softirq_pending的包裹:

#define__raise_softirq_irqoff(nr)do{or_softirq_pending(1UL&

lt;

&

(nr));

}while(0)复制代码raise_softirq_irqoff通过调用__raise_softirq_irqoff实现激活软中断,它的参数nr即位软中断对应的位图槽位:

/**Thisfunctionmustrunwithirqsdisabled!

*/inlinevoidraise_softirq_irqoff(unsignedintnr){//置位图,即标记为可执行状态__raise_softirq_irqoff(nr);

/**Ifwe'

reinaninterruptorsoftirq,we'

redone*(thisalsocatchessoftirq-disabledcode).Wewill*actuallyrunthesoftirqoncewereturnfrom*theirqorsoftirq.**Otherwisewewakeupksoftirqdtomakesurewe*schedulethesoftirqsoon.*///设置了位图后,可以判断是否已经没有在中断上下文中了,如果没有,则是一个立即调用软中断的好时机。

//in_interrupt另一个作用是判断软中断是否被禁用。

//wakeup_softirqd唤醒软中断的守护进程ksoftirq。

if(!

in_interrupt())wakeup_softirqd();

}复制代码现在可以来看"

激活"

软中断的所有含义了,raise_softirq函数完成这一操作:

voidraise_softirq(unsignedintnr){unsignedlongflags;

//所有操作,应该关闭中断,避免嵌套调用local_irq_save(flags);

raise_softirq_irqoff(nr);

local_irq_restore(flags);

}复制代码可见,激活的操作,主要是两点:

1&

gt;

、最重要的,就是置相应的位图,等待将来被处理;

2&

、如果此时已经没有在中断上下文中,则立即调用(其实是内核线程的唤醒操作),现在就是将来;

2、调度时机是的,除了raise_softirq在,可能会(嗯,重要的是“可能”)通过wakeup_softirqd唤醒ksoftirqd外,还得明白软中断的其它调用时机。

A、当do_IRQ完成了I/O中断时调用irq_exit:

#ifdef__ARCH_IRQ_EXIT_IRQS_DISABLED#defineinvoke_softirq()__do_softirq()#else#defineinvoke_softirq()do_softirq()#endifvoidirq_exit(void){account_system_vtime(current);

trace_hardirq_exit();

sub_preempt_count(IRQ_EXIT_OFFSET);

in_interrupt()&

amp;

local_softirq_pending())invoke_softirq();

//调用软中断复制代码B、如果系统使用I/OAPIC,在处理完本地时钟中断时:

void__irq_entrysmp_apic_timer_interrupt(structpt_regs*regs){……irq_exit();

……}复制代码C、local_bh_enablelocal_bh_enable就是打开下半部,当然重中之中就是软中断了:

voidlocal_bh_enable(void){_local_bh_enable_ip((unsignedlong)__builtin_return_address(0));

}staticinlinevoid_local_bh_enable_ip(unsignedlongip){……if(unlikely(!

local_softirq_pending()))do_softirq();

……}复制代码D、在SMP中,当CPU处理完被CALL_FUNCTION_VECTOR处理器间中断所触发的函数时:

唔,对多核中CPU的之间的通信不熟,不太清楚这个机制……3、do_softirq不论是哪种调用方式,最终都会触发到软中断的核心处理函数do_softirq,它处理当前CPU上的所有软中断。

内核将软中断设计尽量与平台无关,但是在某些情况下,它们还是会有差异,先来看一个x8632位的do_softirq版本:

asmlinkagevoiddo_softirq(void){unsignedlongflags;

structthread_info*curctx;

unionirq_ctx*irqctx;

u32*isp;

//软中断不能在中断上下文内嵌套调用。

中断处理程序或下半部采用的是"

方式。

if(in_interrupt())return;

//禁止中断,保存中断标志local_irq_save(flags);

//内核使用一个CPU位图,确实几个软中断可以同时在不同的CPU上运行,包括相同的软中断。

例如,//NET_RX_SOFTIRQ可以同时跑在多个处理器上。

//local_softirq_pending用于确定当前CPU的所有位图是否被设置。

即是否有软中断等待处理。

//回想一下经常发生的网卡接收数据处理:

当网卡中断落在哪一个CPU上时,与之相应的软中断函数就会在其上执行。

//从这里来看,实质就是哪个网卡中断落在相应的CPU上,CPU置其软中断位图,这里做相应的检测(这里local_softirq_pending只//是一个总的判断,后面还有按位的判断),检测到有相应的位,执行之if(local_softirq_pending()){//取得线程描述符curctx=current_thread_info();

//构造中断上下文结构,softirq_ctx是每个CPU的软中断上下文//staticDEFINE_PER_CPU(unionirq_ctx*,softirq_ctx);

//这里先取得当前CPU的软中断上下文,然后为其赋初始值——保存当前进程和栈指针irqctx=__get_cpu_var(softirq_ctx);

irqctx-&

tinfo.task=curctx-&

task;

tinfo.previous_esp=current_stack_pointer;

/*buildthestackframeonthesoftirqstack*///构造中断栈帧isp=(u32*)((char*)irqctx+sizeof(*irqctx));

//call_on_stack切换内核栈,并在中断上下文上执行函数__do_softirqcall_on_stack(__do_softirq,isp);

/**Shouldnthappen,wereturnedaboveifin_interrupt():

*/WARN_ON_ONCE(softirq_count());

}//恢复之local_irq_restore(flags);

}复制代码当配置了CONFIG_4KSTACKS,每个进程的thread_union只有4K,而非8K。

发生中断时,内核栈将不使用进程的内核栈,而使用每个cpu的中断请求栈。

内核栈将使用每个cpu的中断请求栈,而非进程的内核栈来执行软中断函数:

staticvoidcall_on_stack(void*func,void*stack){asmvolatile("

xchgl%%ebx,%%esp\n"

//交换栈指针,中断栈帧的指针stack做为传入参数(%ebx),交换后esp是irq_ctx的栈顶,ebx是进程内核栈的栈"

call*%%edi\n"

//调用软中断函数"

movl%%ebx,%%esp

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1