• LInux中ThreadInfo中的preempt_count字段


    最近看各种上下文,发现和ThreadInfo中的preemption字段密切,于是便调查了下。

    看下Linux源码中的注释:

    /*
    * We put the hardirq and softirq counter into the preemption
    * counter. The bitmask has the following meaning:
    *
    * - bits 0-7 are the preemption count (max preemption depth: 256)
    * - bits 8-15 are the softirq count (max # of softirqs: 256)
    *
    * The hardirq count can in theory reach the same as NR_IRQS.
    * In reality, the number of nested IRQS is limited to the stack
    * size as well. For archs with over 1000 IRQS it is not practical
    * to expect that they will all nest. We give a max of 10 bits for
    * hardirq nesting. An arch may choose to give less than 10 bits.
    * m68k expects it to be 8.
    *
    * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
    * - bit 26 is the NMI_MASK
    * - bit 27 is the PREEMPT_ACTIVE flag
    *
    * PREEMPT_MASK: 0x000000ff
    * SOFTIRQ_MASK: 0x0000ff00
    * HARDIRQ_MASK: 0x03ff0000
    * NMI_MASK: 0x04000000
    */

    这里其实把preempt_count划分成了四部分:抢占计数器、软中断计数、硬件中断计数、NMI计数。

    抢占计数器:0-7位

    软中断计数器:8-15位

    硬中断计数器:16-25位

    NMI标识:26位

    基于上面的信息,看下Linux内核中判断各个上下文的宏:

    #define hardirq_count()    (preempt_count() & HARDIRQ_MASK)
    #define softirq_count()    (preempt_count() & SOFTIRQ_MASK)
    #define irq_count()    (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK   | NMI_MASK))

     可以看到这里判断硬件中断/软中断/中断上下文的实质,就是根据thread_info结构中的preempt_count字段,额忘记列出preempt_count()的实现了:#define preempt_count() (current_thread_info()->preempt_count),这时明白了吧!!!

    不过后面几个掩码的计算有点绕,参考下源码:

    #define __IRQ_MASK(x)    ((1UL << (x))-1)
    
    #define PREEMPT_MASK    (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
    #define SOFTIRQ_MASK    (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
    #define HARDIRQ_MASK    (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
    #define NMI_MASK    (__IRQ_MASK(NMI_BITS)     << NMI_SHIFT)

    实质上就是取对应的位。

    *
     * Are we doing bottom half or hardware interrupt processing?
     * Are we in a softirq context? Interrupt context?
     * in_softirq - Are we currently processing softirq or have bh disabled?
     * in_serving_softirq - Are we currently processing softirq?
     */
    #define in_irq()        (hardirq_count())
    #define in_softirq()        (softirq_count())
    #define in_interrupt()        (irq_count())
    #define in_serving_softirq()    (softirq_count() & SOFTIRQ_OFFSET)

    而这里只是对上面各种计数的包装,只要对应的计数不为0,则表示在对应的上下文中。in_interrupt表示中断上下文,包括了硬件中断、软中断和NMI中断。in_serving_softirq判断是否当前正在处理软中断。

    #define in_nmi()    (preempt_count() & NMI_MASK)

    in_nmi判断当前是否在NMI中断上下文。

    既然如此,咱们再结合内核抢占调度的情况,看下抢占调度函数

    asmlinkage void __sched notrace preempt_schedule(void)
    {
        struct thread_info *ti = current_thread_info();
    
        /*
         * If there is a non-zero preempt_count or interrupts are disabled,
         * we do not want to preempt the current task. Just return..
         */
        if (likely(ti->preempt_count || irqs_disabled()))
            return;
    
        do {
            add_preempt_count_notrace(PREEMPT_ACTIVE);
            __schedule();
            sub_preempt_count_notrace(PREEMPT_ACTIVE);
    
            /*
             * Check again in case we missed a preemption opportunity
             * between schedule and now.
             */
            barrier();
        } while (need_resched());
    }

    可以看到这里进入函数起始,便对当前线程的preempt_count进行了判断,根据上面的介绍,当内核处理任何一个上下文中时,preempt_count均不可能为0,所以我们也可以根据此发现在软中断、硬件中断、禁止内核抢占、NMI上下文中均不允许调度。当然,我们看到后面后又个irqs_disabled,意味着如果当前禁用了硬件中断,则同样不会发生抢占调度。

     补充:

    关闭中断的实质是设置EFLAGS寄存器的IF标志位,CLI指令可执行这一操作,当标志位被设置为0时,表示当前关闭中断状态,而STI指令开中断,二者匹配使用。这里的中断指的是可屏蔽的硬件中断。

    参考资料:

    LInux3.10.1内核源码

  • 相关阅读:
    监控组策略应用组策略建模
    win7加域出现桌面文件丢失和映射驱动器丢失解决办法
    通过windows server 2008 AD域服务器之组策略关闭默认windows共享
    Win 2008 R2 AD组策略统一域用户桌面背景
    Win7+Ubuntu11.10(EasyBCD硬盘安装)
    组策略复制失败排错思路实例
    Windows Server 2008 R2搭建域环境中遇到的一个小错误的解决办法
    通过windows server 2008 AD域服务器之组策略关闭默认windows共享
    无需写try/catch,也能正常处理异常
    [原]《Web前端开发修炼之道》读书笔记JavaScript部分
  • 原文地址:https://www.cnblogs.com/ck1020/p/6576090.html
Copyright © 2020-2023  润新知