ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:35.70KB ,
资源ID:11831830      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/11831830.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(linux软中断浅析.docx)为本站上传会员【仙人****88】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

linux软中断浅析.docx

1、1、软中断 软中断的原理就略过了,讲内核的书上都有,此处省略1500字。。。。。。 1.1 注册 还是以我最熟悉的两个老朋友做为开篇:         open_softirq(NET_TX_SOFTIRQ, net_tx_action);         open_softirq(NET_RX_SOFTIRQ, net_rx_action); open_softirq向内核注册一个软中断,其实质是设置软中断向量表相应槽位,注册其处理函数: 1. void open_softirq(int nr, void (*action)(struct softirq_act

2、ion *)) 2. { 3.         softirq_vec[nr].action = action; 4. } 复制代码 softirq_vec是整个软中断的向量表: 1. struct softirq_action 2. { 3.         void        (*action)(struct softirq_action *); 4. }; 5. 6. static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp; 复制代码 NR_SOFTIR

3、QS是最大软中断向量数,内核支持的所有软中断如下: 1. enum 2. { 3.         HI_SOFTIRQ=0, 4.         TIMER_SOFTIRQ, 5.         NET_TX_SOFTIRQ, 6.         NET_RX_SOFTIRQ, 7.         BLOCK_SOFTIRQ, 8.         TASKLET_SOFTIRQ, 9.         SCHED_SOFTIRQ, 10.         HRTIMER_SOFTIRQ, 11.         RCU_SOFTIRQ,        /* P

4、referable RCU should always be the last softirq */ 12. 13.         NR_SOFTIRQS 14. }; 复制代码 好像后为为RPS新增了一个,不过这我的内核版本偏低。 1.2 激活  当需要调用软中断时,需要调用raise_softirq函数激活软中断,这里使用术语“激活”而非“调用”, 是因为在很多情况下不能直接调用软中断。所以只能快速地将其标志为“可执行”,等待未来某一时刻调用。 为什么“在很多情况下不能直接调用软中断”?试想一下下半部引入的理念,就是为了让上半部更快地执行。 如果在中断程序代码

5、中直接调用软中断函数,那么就失去了上半部与下半部的区别,也就是失去了其存在的意义。 内核使用一个名为__softirq_pending的位图来描述软中断,每一个位对应一个软中断,位图包含在结构irq_stat中: 1. typedef struct { 2.         unsigned int __softirq_pending; 3.         …… 4. } ____cacheline_aligned irq_cpustat_t; 5. 6. DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); 复

6、制代码 宏or_softirq_pending用于设置相应的位(位或操作): 1. #define or_softirq_pending(x)        percpu_or(irq_stat.__softirq_pending, (x)) 复制代码 local_softirq_pending用于取得整个位图(而非某一位): 1. #define local_softirq_pending()        percpu_read(irq_stat.__softirq_pending) 复制代码 宏__raise_softirq_irqoff是or_softirq_pendin

7、g的包裹: 1. #define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0) 复制代码 raise_softirq_irqoff通过调用__raise_softirq_irqoff实现激活软中断,它的参数nr即位软中断对应的位图槽位: 1. /* 2. * This function must run with irqs disabled! 3. */ 4. inline void raise_softirq_irqoff(unsigned int nr) 5. {

8、6.         //置位图,即标记为可执行状态 7.         __raise_softirq_irqoff(nr); 8. 9.         /* 10.          * If we're in an interrupt or softirq, we're done 11.          * (this also catches softirq-disabled code). We will 12.          * actually run the softirq once we return from 13.          * the ir

9、q or softirq. 14.          * 15.          * Otherwise we wake up ksoftirqd to make sure we 16.          * schedule the softirq soon. 17.          */ 18.         //设置了位图后,可以判断是否已经没有在中断上下文中了,如果没有,则是一个立即调用软中断的好时机。 19.         //in_interrupt另一个作用是判断软中断是否被禁用。 20.         //wakeup_softirqd唤醒软中断的守护进

10、程ksoftirq。 21.         if (!in_interrupt()) 22.                 wakeup_softirqd(); 23. } 复制代码 现在可以来看"激活"软中断的所有含义了,raise_softirq函数完成这一操作: 1. void raise_softirq(unsigned int nr) 2. { 3.         unsigned long flags; 4. 5.         //所有操作,应该关闭中断,避免嵌套调用 6.         local_irq_save(flags); 7.    

11、     raise_softirq_irqoff(nr); 8.         local_irq_restore(flags); 9. } 复制代码 可见,激活的操作,主要是两点: <1>、最重要的,就是置相应的位图,等待将来被处理; <2>、如果此时已经没有在中断上下文中,则立即调用(其实是内核线程的唤醒操作),现在就是将来; 2、调度时机 是的,除了raise_softirq在,可能会(嗯,重要的是“可能”)通过wakeup_softirqd唤醒ksoftirqd外,还得明白软中断的其它调用时机。 A、当do_IRQ完成了I/O中断时调用irq_exit:

12、 1. #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED 2. # define invoke_softirq()        __do_softirq() 3. #else 4. # define invoke_softirq()        do_softirq() 5. #endif 6. 7. void irq_exit(void) 8. { 9.         account_system_vtime(current); 10.         trace_hardirq_exit(); 11.         sub_preempt

13、count(IRQ_EXIT_OFFSET); 12.         if (!in_interrupt() && local_softirq_pending()) 13.                 invoke_softirq();                //调用软中断 复制代码 B、如果系统使用I/O APIC,在处理完本地时钟中断时: 1. void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) 2. { 3.         …… 4.         irq_exit(); 5

14、         …… 6. } 复制代码 C、local_bh_enable local_bh_enable就是打开下半部,当然重中之中就是软中断了: 1. void local_bh_enable(void) 2. { 3.         _local_bh_enable_ip((unsigned long)__builtin_return_address(0)); 4. } 5. 6. static inline void _local_bh_enable_ip(unsigned long ip) 7. { 8.         …… 9. 10.  

15、       if (unlikely(!in_interrupt() && local_softirq_pending())) 11.                 do_softirq(); 12. 13.         …… 14. } 复制代码 D、在SMP中,当CPU处理完被CALL_FUNCTION_VECTOR处理器间中断所触发的函数时: 唔,对多核中CPU的之间的通信不熟,不太清楚这个机制……  3、do_softirq 不论是哪种调用方式,最终都会触发到软中断的核心处理函数do_softirq,它处理当前CPU上的所有软中断。 内核将软中断设计

16、尽量与平台无关,但是在某些情况下,它们还是会有差异,先来看一个x86 32位的do_softirq版本: 1. asmlinkage void do_softirq(void) 2. { 3.         unsigned long flags; 4.         struct thread_info *curctx; 5.         union irq_ctx *irqctx; 6.         u32 *isp; 7. 8.         //软中断不能在中断上下文内嵌套调用。中断处理程序或下半部采用的是"激活"方式。 9.         if (i

17、n_interrupt()) 10.                 return; 11. 12.         //禁止中断,保存中断标志 13.         local_irq_save(flags); 14.         //内核使用一个CPU位图,确实几个软中断可以同时在不同的CPU上运行,包括相同的软中断。例如, 15.         //NET_RX_SOFTIRQ可以同时跑在多个处理器上。 16.         //local_softirq_pending用于确定当前CPU的所有位图是否被设置。即是否有软中断等待处理。 17.         /

18、/回想一下经常发生的网卡接收数据处理:当网卡中断落在哪一个CPU上时,与之相应的软中断函数就会在其上执行。 18.         //从这里来看,实质就是哪个网卡中断落在相应的CPU上,CPU置其软中断位图,这里做相应的检测(这里local_softirq_pending只 19.         //是一个总的判断,后面还有按位的判断),检测到有相应的位,执行之 20.         if (local_softirq_pending()) { 21.                 //取得线程描述符 22.                 curctx = current_

19、thread_info(); 23.                 //构造中断上下文结构,softirq_ctx是每个CPU的软中断上下文 24.                 //static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx); 25.                 //这里先取得当前CPU的软中断上下文,然后为其赋初始值——保存当前进程和栈指针 26.                 irqctx = __get_cpu_var(softirq_ctx); 27.                 irqctx->ti

20、nfo.task = curctx->task; 28.                 irqctx->tinfo.previous_esp = current_stack_pointer; 29. 30.                 /* build the stack frame on the softirq stack */ 31.                 //构造中断栈帧 32.                 isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); 33. 34.                

21、//call_on_stack切换内核栈,并在中断上下文上执行函数__do_softirq 35.                 call_on_stack(__do_softirq, isp); 36.                 /* 37.                  * Shouldnt happen, we returned above if in_interrupt(): 38.                  */ 39.                 WARN_ON_ONCE(softirq_count()); 40.         } 41.

22、 42.         //恢复之 43.         local_irq_restore(flags); 44. } 复制代码 当配置了CONFIG_4KSTACKS,每个进程的thread_union只有4K,而非8K。发生中断时,内核栈将不使用进程的内核栈,而使用每个 cpu的中断请求栈。 内核栈将使用每个 cpu的中断请求栈,而非进程的内核栈来执行软中断函数: 1. static void call_on_stack(void *func, void *stack) 2. { 3.         asm volatile("xchgl        %%ebx,

23、esp        \n"                                //交换栈指针,中断栈帧的指针stack做为传入参数(%ebx),交换后esp是irq_ctx的栈顶,ebx是进程内核栈的栈 4.                      "call        *%%edi                \n"                                        //调用软中断函数 5.                      "movl        %%ebx,%%esp        \n"               

24、                        //恢复之,直接使用movl,而非xchgl是因为函数执行完毕,中断的栈帧指针已经没有用处了 6.                      : "=b" (stack) 7.                      : "0" (stack), 8.                        "D"(func) 9.                      : "memory", "cc", "edx", "ecx", "eax"); 10. } 复制代码 PS:所有的这些执行,应该都是在定义4K栈的基础上的: 1. #

25、ifdef CONFIG_4KSTACKS 2. /* 3. * per-CPU IRQ handling contexts (thread information and stack) 4. */ 5. union irq_ctx { 6.         struct thread_info      tinfo; 7.         u32                     stack[THREAD_SIZE/sizeof(u32)]; 8. } __attribute__((aligned(PAGE_SIZE))); 9. 10. static DEFINE_

26、PER_CPU(union irq_ctx *, hardirq_ctx); 11. static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx); 12. …… 13. 14. static void call_on_stack(void *func, void *stack) 15. …… 复制代码 是的,这个版本相对复杂,但是如果看了复杂的,再来看简单的,就容易多了,当平台没有定义do_softirq函数时(__ARCH_HAS_DO_SOFTIRQ), 内核提供了一个通用的: 1. #ifndef __ARCH_HAS_DO_

27、SOFTIRQ 2. 3. asmlinkage void do_softirq(void) 4. { 5.         __u32 pending; 6.         unsigned long flags; 7. 8.         if (in_interrupt()) 9.                 return; 10. 11.         local_irq_save(flags); 12. 13.         pending = local_softirq_pending(); 14. 15.         if (pendi

28、ng) 16.                 __do_softirq(); 17. 18.         local_irq_restore(flags); 19. } 20. 21. #endif 复制代码 无需更多的解释,它非常的简洁。 不论是哪个版本,都将调用__do_softirq函数: 1. asmlinkage void __do_softirq(void) 2. { 3.         struct softirq_action *h; 4.         __u32 pending; 5.         int max_restart

29、 = MAX_SOFTIRQ_RESTART; 6.         int cpu; 7. 8.         //保存位图 9.         pending = local_softirq_pending(); 10.         //进程记帐 11.         account_system_vtime(current); 12. 13.         //关闭本地CPU下半部。为了保证同一个CPU上的软中断以串行方式执行。 14.         __local_bh_disable((unsigned long)__builtin_return_ad

30、dress(0)); 15.         lockdep_softirq_enter(); 16. 17.         //获取本地CPU 18.         cpu = smp_processor_id(); 19. restart: 20.         /* Reset the pending bitmask before enabling irqs */ 21.         //清除位图 22.         set_softirq_pending(0); 23. 24.         //锁中断,只是为了保持位图的互斥,位图处理完毕。后面的代

31、码可以直接使用保存的pending, 25.         //而中断处理程序在激活的时候,也可以放心地使用irq_stat.__softirq_pending。 26.         //所以,可以开中断了 27.         local_irq_enable(); 28. 29.         //取得软中断向量 30.         h = softirq_vec; 31. 32.         //循环处理所有的软中断 33.         do { 34.                 //逐步取位图的每一位,判断该位上是否有软中断被设置。若有,

32、处理之 35.                 if (pending & 1) { 36.                         //保存抢占计数器 37.                         int prev_count = preempt_count(); 38.                         kstat_incr_softirqs_this_cpu(h - softirq_vec); 39. 40.                         trace_softirq_entry(h, softirq_vec); 41.  

33、                      //调用软中断 42.                         h->action(h); 43.                         trace_softirq_exit(h, softirq_vec); 44.                         //判断软中断是否被抢占,如果是,则输出一段错误信息 45.                         if (unlikely(prev_count != preempt_count())) { 46.                          

34、       printk(KERN_ERR "huh, entered softirq %td %s %p" 47.                                        "with preempt_count %08x," 48.                                        " exited with %08x?\n", h - softirq_vec, 49.                                        softirq_to_name[h - softirq_vec], 50.      

35、                                  h->action, prev_count, preempt_count()); 51.                                 preempt_count() = prev_count; 52.                         } 53.                         //??qsctr,这个是啥东东 54.                         rcu_bh_qsctr_inc(cpu); 55.                 } 56.  

36、               //指向下一个软中断槽位 57.                 h++; 58.                 //移位,取下一个软中断位 59.                 pending >>= 1; 60.         } while (pending); 61. 62.         //当软中断处理完毕后,因为前面已经开了中断了,所以有可能新的软中断已经又被设置, 63.         //软中断调度程序会尝试重新软中断,其最大重启次数由max_restart决定。 64.         //所以,这里必须再次关闭中断,

37、再来一次…… 65.         local_irq_disable(); 66. 67.         //取位图 68.         pending = local_softirq_pending(); 69.         //有软中断被设置,且没有超过最大重启次数,再来一次先 70.         if (pending && --max_restart) 71.                 goto restart; 72. 73.         //超过最大重启次数,还有软中断待处理,调用wakeup_softirqd。其任处是唤醒软中断守护进

38、程ksoftirqd。 74.         if (pending) 75.                 wakeup_softirqd(); 76. 77.         lockdep_softirq_exit(); 78. 79.         account_system_vtime(current); 80.         //恢复下半部 81.         _local_bh_enable(); 82. } 复制代码 中断跟踪 如果中断跟踪CONFIG_TRACE_IRQFLAGS被定义,lockdep_softirq_enter/lockdep_softirq_exit用于递增/递减当前进程的软中断上下文计数器softirq_context: 1. # define lockdep_softirq_enter()        do { current->softirq_context++; } while (0) 2. # define lockdep_softirq_exit()        do { current->softirq_context--; } while (0) 复制代码 trace_softirq_entry与trace_softirq_exit配合使用,可以用于判断软中断的延迟。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服