免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6325 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-处理器间中断-接收处理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-07-06 16:16 |只看该作者 |倒序浏览
[从"处理器间中断-发送"中的描述可知]:
#define        IPI_BITMAP_VECTOR    249
#define IPI_PREEMPT          1
1:已经给cpu5发送了一个中断向量号为IPI_BITMAP_VECTOR的IPI。
2:并且数组元素cpu_ipi_pending[5]的第IPI_PREEMPT个bit位被设置为1。

[从"内核如何实现IA32中断处理"中的描述可知]:
中断向量号为IPI_BITMAP_VECTOR对应的中断处理程序为函数IDTVEC(ipi_intr_bitmap_handler)。


此时,cpu5接收到了这个IPI,在执行中断处理程序IDTVEC(ipi_intr_bitmap_handler)前,cpu硬件单元要做一些处理,硬件单元所做的处理可以参考
"内核如何实现IA32中断处理"结尾的描述。

这里做下面的假设:
1:接收到这个IPI时,cpu5运行在用户态。
2:接收到这个IPI时,正在cpu5运行的线程对应的struct thread对象简记为cur_thread。
3:cpu硬件单元已经完成了在执行中断处理程序之前的处理。

此时cpu5运行在内核态,开始执行中断处理程序IDTVEC(ipi_intr_bitmap_handler),线程cur_thread的内核栈如下所示:
  1. ******************************* 内核栈顶部 高地址方向
  2. *                             *
  3. *   struct pcb对象            *
  4. *                             *
  5. *                             *
  6. ******************************* <--cur_thread的td_pcb成员指向这里
  7. *                             *
  8. *   16bytes for vm            *        
  9. ******************************* <--cur_thread的内核栈栈顶                        
  10. *   SS                        *
  11. *******************************
  12. *   ESP                       *
  13. *******************************
  14. *   EFLAGS                    *
  15. *******************************
  16. *   CS                        *
  17. *******************************
  18. *   EIP                       *     
  19. ******************************* <--执行中断处理程序IDTVEC(ipi_intr_bitmap_handler)时,esp指向这里
  20. *   SS                        *
  21. *******************************
  22. *   0                         *
  23. *******************************
  24. *   0                         *
  25. *******************************
  26. *   EAX                       *
  27. *******************************
  28. *   ECX                       *
  29. *******************************
  30. *   EDX                       *
  31. *******************************
  32. *   EBX                       *
  33. *******************************   通过struct trapframe类型的数据对象来描述
  34. *   ESP                       *
  35. *******************************
  36. *   EBP                       *
  37. *******************************
  38. *   ESI                       *
  39. *******************************
  40. *   EDI                       *
  41. *******************************
  42. *   DS                        *
  43. *******************************
  44. *   ES                        *
  45. *******************************
  46. *   FS                        *
  47. ******************************* <--宏PUSH_FRAME和SET_KERNEL_SREGS执行完后,esp指向这里
  48. *  addr(jmp        doreti)       *
  49. ******************************* <-- 执行call ipi_bitmap_handler指令时esp指向这里
  50. *                             *
  51. *                             *
  52. *                             *
  53. *                             *
  54. *                             *
  55. *                             *
  56. *                             *
  57. *                             *
  58. *                             *
  59. *                             *
  60. *******************************------ 内核栈底部 低地址方向
复制代码
[IDTVEC(ipi_intr_bitmap_handler)]-中断向量号IPI_BITMAP_VECTOR对应的中断处理程序:
  1.    304        IDTVEC(ipi_intr_bitmap_handler)       
  2. /*******************************************************************************
  3. * 305,宏PUSH_FRAME,该宏如下所示:
  4.    将线程cur_thread的用户态硬件上下文的一部分压入内核栈中。

  5.    306,宏SET_KERNEL_SREGS,如下所示:
  6.    设置内核使用的段寄存器。

  7.    307:
  8.    清DF标志,string operations increment the index registers (ESI and/or EDI).
  9. ******************************************************/
  10.    305                PUSH_FRAME
  11.    306                SET_KERNEL_SREGS
  12.    307                cld
  13.    308                
  14. /*******************************************************************
  15. * 309-310:
  16.    通过lapic访问cpu5的local APIC寄存器组。

  17.    这里将对local APIC寄存器组中的EOI Register执行一个写操作,这是
  18.    APIC要求的,作为对这个写操作的响应,cpu将:
  19.    Upon receiving an EOI, the APIC clears the highest
  20.    priority bit in the ISR and dispatches the next highest
  21.    priority interrupt to the processor
  22. **********************************************/
  23.    309                movl        lapic, %edx
  24.    310                movl        $0, LA_EOI(%edx)        /* End Of Interrupt to APIC */
  25.    311               
  26.    312                FAKE_MCOUNT(TF_EIP(%esp))
  27.    313       
  28. /**********************************************************************
  29. * 314:
  30.    通过上面内核栈的布局,可以明显的看出,函数ipi_bitmap_handler
  31.    的参数是一个struct trapframe类型的对象,而不是指向这个对象的指针。

  32.    316:
  33.    doreti函数完成返回中断前的处理,这个暂时略过。
  34. *********************************/
  35.    314                call        ipi_bitmap_handler
  36.    315                MEXITCOUNT
  37.    316                jmp        doreti
  38.    317        #endif
复制代码
[宏PUSH_FRAME]:
  1. /*****************************************************************************************
  2. * Macros to create and destroy a trap frame.
  3.    pushal指令:
  4.    Pushes the contents of the general-purpose registers onto the stack. The registers
  5.    are stored on the stack in the following order: EAX, ECX, EDX, EBX, ESP (original
  6.    value), EBP, ESI, and EDI (if the current operand-size attribute is 32)。
  7. *********************************************/
  8.    145        #define        PUSH_FRAME                                                        \
  9.    146                pushl        $0 ;                /* dummy error code */                        \
  10.    147                pushl        $0 ;                /* dummy trap type */                        \
  11.    148                pushal ;                /* 8 ints */                                \
  12.    149                pushl        %ds ;                /* save data and extra segments ... */        \
  13.    150                pushl        %es ;                                                        \
  14.    151                pushl        %fs
复制代码
[宏SET_KERNEL_SREGS]:
  1. /**********************************************************************************
  2. * Setup the kernel segment registers.
  3.    此时cpu5运行在内核态,段寄存器也要更改。
  4.    
  5.    173-175:
  6.    用内核数据段的segment selector,即KDSEL加载DS,ES两个寄存器,访问内核数据。

  7.    176-177:
  8.    用KPSEL加载FS寄存器,这样就能访问数据对象__pcpu[5],也是宏PCPU_*的基础。   
  9. ******************************************/
  10.    172        #define        SET_KERNEL_SREGS                                                \
  11.    173                movl        $KDSEL, %eax ;        /* reload with kernel's data segment */        \
  12.    174                movl        %eax, %ds ;                                                \
  13.    175                movl        %eax, %es ;                                                \
  14.    176                movl        $KPSEL, %eax ;        /* reload with per-CPU data segment */        \
  15.    177                movl        %eax, %fs
复制代码
[函数ipi_bitmap_handler]:
  1. /***********************************************************************
  2. * 参数描述:
  3.    frame:用来访问保存在线程cur_thread内核栈上用户态硬件上下文。
  4. ****************************/
  5.   1355        void
  6.   1356        ipi_bitmap_handler(struct trapframe frame)
  7.   1357        {
  8. /***************************************************************************
  9. * 1360,cpu:PCPU_GET宏获取当前cpu的logical cpu id,这里为5.
  10. *******************************/
  11.   1358                struct trapframe *oldframe;
  12.   1359                struct thread *td;
  13.   1360                int cpu = PCPU_GET(cpuid);
  14.   1361                u_int ipi_bitmap;
  15. /**************************************************************************
  16. * 1364:td指向当前正在运行线程的struct thread对象,这里为&cur_thread。

  17.    1365:
  18.    递增td_intr_nesting_level,即递增中断嵌套层数。

  19.    1366-1367:
  20.    struct thread对象的td_intr_frame成员,freebsd8.3中没有该成员,添加的
  21.    这个成员个人理解为,该成员在中断处理程序中使用,用来访问保存在线程
  22.    内核栈上的硬件上下文。

  23.    1368:
  24.    函数atomic_readandclear_int返回数组元素cpu_ipi_pending[5]的值,然后
  25.    将其清零。
  26. *****************************/
  27.   1363                critical_enter();
  28.   1364                td = curthread;
  29.   1365                td->td_intr_nesting_level++;
  30.   1366                oldframe = td->td_intr_frame;
  31.   1367                td->td_intr_frame = &frame;
  32.   1368                ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
  33. /****************************************************************************
  34. * 三个特殊的IPI如下:
  35. * #define IPI_AST                0        
  36.    #define IPI_PREEMPT          1
  37.    #define IPI_HARDCLOCK        2

  38. * 1369-1386:
  39.    依次测试变量的ipi_bitmap的第1,0,2个比特位,检查发送
  40.    的是上面三个特殊IPI的哪一个,并递增相应的计数器。

  41.    1369-1374:
  42.    发送的是IPI_PREEMPT,此时调用调度程序相关的sched_preempt函数,当
  43.    sched_preempt函数执行完后,cpu5上的线程cur_thread被成功抢占。

  44.    1375-1380:
  45.    发送的是IPI_AST,此时不做处理。

  46.    1381-1386:
  47.    发送的是IPI_HARDCLOCK,此时调用函数hardclockintr。
  48. ******************************************************/
  49.   1369                if (ipi_bitmap & (1 << IPI_PREEMPT)) {
  50.   1370        #ifdef COUNT_IPIS
  51.   1371                        (*ipi_preempt_counts[cpu])++;
  52.   1372        #endif
  53.   1373                        sched_preempt(td);
  54.   1374                }
  55.   1375                if (ipi_bitmap & (1 << IPI_AST)) {
  56.   1376        #ifdef COUNT_IPIS
  57.   1377                        (*ipi_ast_counts[cpu])++;
  58.   1378        #endif
  59.   1379                        /* Nothing to do for AST */
  60.   1380                }
  61.   1381                if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
  62.   1382        #ifdef COUNT_IPIS
  63.   1383                        (*ipi_hardclock_counts[cpu])++;
  64.   1384        #endif
  65.   1385                        hardclockintr();
  66.   1386                }
  67. /********************************************************
  68. * 1387:将td_intr_frame成员恢复到之前的值。
  69.    1388:递减td_intr_nesting_level,即中断嵌套数减1.
  70. *******************************/
  71.   1387                td->td_intr_frame = oldframe;
  72.   1388                td->td_intr_nesting_level--;
  73.   1389                critical_exit();
  74.   1390        }
复制代码
[ULE线程调度-sched_preempt函数]:
  1. /*******************************************************************
  2. * 函数sched_preempt就是调用mi_switch函数执行一个线程切换,执行
  3.    完后,线程cur_thread被成功抢占。

  4.    2130:tdq此时为&tdq_cpu[5].
  5.    2132:将tdq_ipipending设置为0,表示相应的IPI已经处理。

  6.    2133-2143:
  7.    再次检查是否需要抢占线程cur_thread,这里简单的比较两个优先级。
  8.    如果需要抢占,就设置合适的标志来调用mi_switch函数完成线程切换。
  9. ***********************************/
  10.   2122        void
  11.   2123        sched_preempt(struct thread *td)
  12.   2124        {
  13.   2125                struct tdq *tdq;
  14.   2126       
  15.   2127                SDT_PROBE2(sched, , , surrender, td, td->td_proc);
  16.   2128       
  17.   2129                thread_lock(td);
  18.   2130                tdq = TDQ_SELF();
  19.   2131                TDQ_LOCK_ASSERT(tdq, MA_OWNED);
  20.   2132                tdq->tdq_ipipending = 0;
  21.   2133                if (td->td_priority > tdq->tdq_lowpri) {
  22.   2134                        int flags;
  23.   2135       
  24.   2136                        flags = SW_INVOL | SW_PREEMPT;
  25.   2137                        if (td->td_critnest > 1)
  26.   2138                                td->td_owepreempt = 1;
  27.   2139                        else if (TD_IS_IDLETHREAD(td))
  28.   2140                                mi_switch(flags | SWT_REMOTEWAKEIDLE, NULL);
  29.   2141                        else
  30.   2142                                mi_switch(flags | SWT_REMOTEPREEMPT, NULL);
  31.   2143                }
  32.   2144                thread_unlock(td);
  33.   2145        }]
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP