基本逻辑
一个计算机系统可能支持各种watchdog,比如可以使用一个专用的watchdog硬件设备,这个
硬件设备是一个计数器,计数器超时会触发告警,我们每隔一段时清理下这个计数器,这样
在系统正常时,总不会触发计数器超时告警,反过来讲,当计数器超时告警时,我们推断系
统发生了异常,异常导致无法及时清理这个计数器。
Linux内核基于PMU counter实现了watchdog,这种实现要求PMU counter的中断要是不可屏
蔽中断(NMI)。基本逻辑是,soft lockup的hrtimer超时处理里会更新相关的标记(hrtimer_interrupts),
PMU counter的益处中断处理函数里检测hrtimer_interrupts有没有被更新,如果一定时间
没有被更新,那么说明hrtime的中断得不到处理,就判断发生了异常。
Linux内核把这种异常叫做hard lockup,基于PMU counter的watchdog是hard lockup的一种
实现方式。对应的,Linux内核也有soft lockup的特性,具体逻辑可以参考这里。
代码分析
内核初始化时会调用lockup_detector_init,这里是soft lockup和hard lockup的入口,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| lockup_detector_init /* kernel/watchdog_perf.c */ +-> watchdog_hardlockup_probe
/* 先检测当前硬件平台上有没有支持NMI中断的PMU */ +-> arch_perf_nmi_is_available
/* 有NMI中断的PMU, 使用PMU的counter中断(配置成NMI)检测hard lockup */ +-> hardlockup_detector_event_create /* 根据watchdog_thresh计算counter的采样间隔 */ +-> wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh) /* 注册PMU event */ +-> perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL) /* 更新watchdog_ev为如上得到perf_event*/ +-> this_cpu_write(watchdog_ev, evt)
/* 对于soft lockup打开的情况,在soft lockup后重新启动hard lockup */ +-> lockup_detector_setup +-> if (watchdog_enabled && watchdog_thresh) softlockup_start_all() /* 目前是空函数?*/ +-> watchdog_hardlockup_start() /* ?*/ +-> __lockup_detector_cleanup()
watchdog_overflow_callback +-> watchdog_check_timestamp +-> watchdog_hardlockup_check /* * 通过检测hrtimer_interrupts变量是否更新来判断hard lockup,而hrtimer_interrupts * 这个变量是在soft lockup的hrtimer处理函数中更新的。如果这个变量不变化, * 表示一段时间都没有hrtimer中断,判断发生了hard lockup。 * * 可见关中断的时间如果太长就会触发hard lockup。 */ +-> is_hardlockup(cpu)
|