调度器37—关中断/关抢占Debug-2-CONFIG_TRACE_IRQFLAGS 的作用

一、梳理

基于 msm-4.4

注: 本文主要用于求证使能 CONFIG_TRACE_IRQFLAGS 与否的区别。

若使能后会多出下面定义:

//kernel/msm-4.4/include/linux/irqflags.h 
#ifdef CONFIG_TRACE_IRQFLAGS
    extern void trace_softirqs_on(unsigned long ip);
    extern void trace_softirqs_off(unsigned long ip);
    extern void trace_hardirqs_on(void);
    extern void trace_hardirqs_off(void);
    #define trace_hardirq_context(p)    ((p)->hardirq_context)
    #define trace_softirq_context(p)    ((p)->softirq_context)
    #define trace_hardirqs_enabled(p)    ((p)->hardirqs_enabled)
    #define trace_softirqs_enabled(p)    ((p)->softirqs_enabled)
    #define trace_hardirq_enter()    do { current->hardirq_context++; } while (0)
    #define trace_hardirq_exit()    do { current->hardirq_context--; } while (0)
    #define lockdep_softirq_enter()    do { current->softirq_context++; } while (0)
    #define lockdep_softirq_exit()    do { current->softirq_context--; } while (0)
    #define INIT_TRACE_IRQFLAGS    .softirqs_enabled = 1,


1. trace_softirqs_on

若不包括 trace_irqsoff.c 和 lockdep.c(它里面自己实现的) 的话,只有一处使用:

    __do_softirq //softirq.c
    _local_bh_enable //softirq.c
        __local_bh_enable //softirq.c
            if (softirq_count() == (cnt & SOFTIRQ_MASK)) //软中断部分计数要减为0时调用
                trace_softirqs_on(_RET_IP_);

软中断不可以嵌套执行。

==> 小结: 软中断部分计数要减为0时调用 trace_softirqs_on()


2. trace_softirqs_off

若不包括 trace_irqsoff.c 和 lockdep.c(它里面自己实现的) 的话,只有一处使用:

    _raw_spin_lock_bh_nested //spinlock.c 若使能 CONFIG_DEBUG_LOCK_ALLOC 才调用
    __do_softirq //softirq.c 传参(_RET_IP_, SOFTIRQ_OFFSET) 置位bit8表示正在执行软中断
    __raw_read_lock_bh //rwlock_api_smp.h 传参 (_RET_IP_, SOFTIRQ_LOCK_OFFSET)同时置位bit9和bit0
    __raw_write_lock_bh //rwlock_api_smp.h 传参(_RET_IP_, SOFTIRQ_LOCK_OFFSET)
    __raw_spin_lock_bh //spinlock_api_smp.h 传参(_RET_IP_, SOFTIRQ_LOCK_OFFSET)
    __raw_spin_trylock_bh //spinlock_api_smp.h 传参(_RET_IP_, SOFTIRQ_LOCK_OFFSET)
    local_bh_disable //bottom_half.h 传参 (_THIS_IP_, SOFTIRQ_DISABLE_OFFSET)
        __local_bh_disable_ip(ip, cnt) //softirq.c
            __preempt_count_add(cnt);
            if (softirq_count() == (cnt & SOFTIRQ_MASK))
                trace_softirqs_off(ip);

==>小结: 当抢占计数部分由0变为非0的时候执行。

总结:由这两个trace可知,若是想监控关软中断临界区(包括正在执行软中断),可以使用 trace_softirqs_on()/trace_softirqs_off().


3. trace_hardirqs_on

若不包括 trace_irqsoff.c 的话,只有一处使用:

    local_irq_enable() //irqflags.h
        do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)

    local_irq_restore(flags) //irqflags.h
        trace_hardirqs_on()

    safe_halt() //irqflags.h
        do { trace_hardirqs_on(); raw_safe_halt(); } while (0)

    do_debug_exception //fault.c 
        if (interrupts_enabled(regs))
            trace_hardirqs_on();

    el1_irq: //entry.S 的退出
        trace_hardirqs_on();

    el0_irq: //entry.S 的退出
    el0_irq_naked: //entry.S 的退出
        bl trace_hardirqs_on

这是监控长时间关中断所需要的。


4. trace_hardirqs_off

若不包括 trace_irqsoff.c 和 lockdep.c(它里面自己实现的) 的话:

    local_irq_disable()
        do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)

    local_irq_save(flags)
        do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0)

    local_irq_restore(flags)
        trace_hardirqs_off();

    secondary_start_kernel //smp.c idle进程上下文
        trace_hardirqs_off()

    do_debug_exception //fault.c 这就要求在函数内判断中断是关闭的
        if (interrupts_enabled(regs))
            trace_hardirqs_off();

    el1_irq: //entry.S 的入口
        bl    trace_hardirqs_off

    el0_ia: //entry.S 的入口
        bl    trace_hardirqs_off

    el0_irq: //entry.S 的入口
    el0_irq_naked: //entry.S 的入口
        bl    trace_hardirqs_off

    work_resched: //entry.S 的入口
        bl    trace_hardirqs_off

小结: 若是想监控关中断持续时长,可以使用 trace_hardirqs_off()/trace_hardirqs_on() 这两个回调。


5. trace_hardirq_context

    __do_softirq //softirq.c
        lockdep_softirq_start //softirq.c 下面不为0返回true
            trace_hardirq_context(current)

        print_usage_bug //lockdep.c 在打印中获取这些信息 //默认不使能
            printk(trace_hardirq_context(curr))

===> 小结: 这个若使能了 lockdep 有用,否则上什么作用也没起到。


6. trace_softirq_context

    print_usage_bug //lockdep.c 
        printk(trace_softirq_context(curr))

===> 小结: 这个只有 lockdep 中使用。


7. trace_hardirqs_enabled

    print_usage_bug
        printk(trace_hardirqs_enabled(curr))

===> 小结: 这个只有 lockdep 中使用。


8. trace_softirqs_enabled

    print_usage_bug
        printk(trace_softirqs_enabled(curr))

===> 小结: 这个只有 lockdep 中使用。


9. trace_hardirq_enter

__do_softirq //softirq.c
    lockdep_softirq_end(in_hardirq) //softirq.c
        if (in_hardirq)
            trace_hardirq_enter();

    __irq_enter() //hardirq.h 表示正在执行硬中断回调时执行
        trace_hardirq_enter();

    nmi_enter() //hardirq.h
        trace_hardirq_enter();


10. trace_hardirq_exit

    __do_softirq //softirq.c
        irq_exit //softirq.c 表示硬中断退出
        lockdep_softirq_start() //softirq.c
            if (trace_hardirq_context(current)) {
                in_hardirq = true;
                trace_hardirq_exit();
            }

    __irq_exit //hardirq.h
        trace_hardirq_exit();

    nmi_exit //hardirq.h
        trace_hardirq_exit()

==> 小结: trace_hardirq_enter()/trace_hardirq_exit() 可用来检查硬中断回调执行时长,它只对 current->hardirq_context 进行加加/减减操作,trace_hardirq_context() 返回 current->hardirq_context 的值。


11. lockdep_softirq_enter

    __do_softirq //softirq.c
        lockdep_softirq_start //softirq.c
            lockdep_softirq_enter()


12. lockdep_softirq_exit

    __do_softirq //softirq.c 临近退出时执行
        lockdep_softirq_end(in_hardirq)
            lockdep_softirq_exit(); //current->softirq_context--;
            if (in_hardirq)
                trace_hardirq_enter(); //current->hardirq_context++;

在硬中断上下文之间划出一小块软中断上下文。

 

要注意使能 CONFIG_TRACE_IRQFLAGS 后与 lockdep 中的定义兼容,宏的依赖上要处理一下。

 

posted on 2025-07-24 21:59  Hello-World3  阅读(14)  评论(0)    收藏  举报

导航