【ARM Linux 系统稳定性分析入门及渐进 2 -- Kernel Lockup】


请阅读嵌入式及芯片开发学必备专栏


上篇文章:ARM Linux 系统稳定性分析入门及渐进 1 – Crash 工具简介
下篇文章:ARM Linux 系统稳定性分析入门及渐进 3 – 栈溢出

1.1 SoftLockup

1.1.1 soft lockup 简介

Softlockup(watchdog) 用于检测系统调度是否正常,即软锁的情况,当发生 Softlockup 时,内核不能调度,但还能响应中断,使系统呈现 “软 hung 死的状态”(CPU 上还是有程序在跑着,就是没法让别人来抢占它了而已,所以用户看起来系统不能切换任务了,像 hung 死了一样。

1.1.2 进程分类

Linux 内核中实现了Scheduler Classes,来实现多个调度类(Scheduler class)的协同工作,每个不同的调度类对应不同的类型的线程,而且每个调度类都有自身的优先级,Linux调度管理基础代码会遍历在内核中注册了的调度类,选择高优先级的调度类,然后让此调度类按照自己的调度算法选择下一个执行的线程。Linux系统中常用的几种调度类为:

  • SCHED_OTHER 分时调度策略;
  • SCHED_FIFO 实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃;
  • SCHED_RR 实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平;
  • SCHED_NORMAL 是用于普通线程的调度类,而 SCHED_FIFO 和 SCHED_RR 是用于实时线程的调度类,优先级高于 SCHED_NORMAL。

SCHED_OTHER 是不支持优先级使用的,而 SCHED_FIFOSCHED_RR 支持优先级的使用,他们分别为 199,数值越大优先级越高。

Linux 内核会将大量工作放置在内核线程中,这些线程是在内核地址空间中运行的特殊进程。大多数内核线程运行在 SCHED_NORMAL 类中,必须与普通用户空间进程争夺CPU时间。但是有一些内核线程它的开发者们认为它们非常特殊,应该比用户空间进程要有更高优先级。因此也会把这些内核线程放到 SCHED_FIFO 中去。
无论优先级高低,实时进程都会优先于 SCHED_NORMAL 中的所有进程先执行,因为后者里面都是普通的非实时进程。

1.1.3 Soft lockup 基本原理

内核为每个 CPU 启动一个内核实时线程线程(watchdog/x),优先级最高的实时线程,它会被周期地调度. 这个线程的工作就是写一个变量 watchdog_touch_ts,其实就是把当前 CPU 上维护的一个时间戳写进去。假如该 CPU 上的调度没有问题,那么这个变量的值是会非常新的.假如不是,比如调度器有好久没在这个 CPU 上切换任务了,那么这个时间戳值就会比较旧了。

有一个高精度 hrtimer,它也会周期地被唤醒,时钟处理函数,会去检测这个变量值,假如它发现 watchdog_touch_ts 这个变量值,距离当前最新时间的间隔已经超过了 softlockup 允许的最大时间值(默认是20s,可以设置),它就会报警,如果设置了 /proc/sys/kernel/softlockup_panic,那么它就让系统 panic

hrtimer 依赖中断机制,而中断机制不依赖调度器,所以可以用它来监控调度器工作与否。

watchdog(unsigned int cpu)
    -->__touch_watchdog(); 
    /* 获取当前时间并赋值给 watchdog_touch_ts,
    /* 目的是周期性的检测是否是 soft_lockup*/
    -->__this_cpu_write(watchdog_touch_ts, get_timestamp());

(watchdog/x) 线程优先级最高的实时线程,内核同时会启动周期为4秒hrtimer 定时器(喂看门狗),这个高精度定时器 hrtimer 和 CPU 绑定,使用的变量都是 percpu 的。确保每个CPU之间不相互干扰。

watchdog_enable(unsigned int cpu)
-->hrtimer->function = watchdog_timer_fn; //HRTIMER_RESTART,会周期性的执行
   -->watchdog_check_hardlockup_other_cpu();
   -->wake_up_process(__this_cpu_read(softlockup_watchdog));

因为 hrtimer 超时函数在软中断中调用,在中断产生后会比线程优先得到执行。hrtimer 的回调函数中会判断 watchdog_touch_ts 和当前时间差,如果超过给定值,那就证明内核调度失败,则说明这段时间内都没有发生调度(因为此线程优先级最高),则打印相应告警或根据配置可以进入 panic 流程。

1.1.4 Soft lockup 测试例子

在某个线程里添加如下语句:

 preempt_disable();
    while(1);

然后过会就会打印如下log:

[   28.548865] BUG: soft lockup - CPU#1 stuck for 22s! [us kthread:1106]
[   28.555378] Modules linked in:

1.2 hard lockup 简介

hard lockup 主要是发现某个 cpu 因为长期 disable interrupt 的情况。由于某种原因导致系统处于内核态超过 10s 导致中断无法运行(hard lockup)。由于调度,时钟等重要内核事件都是要时间中断来触发的,现在中断给屏蔽了,就导致这一切都无法触发,不说调度,连各种重要的时钟事件都无法处理了。系统基本啥也干不了了,所以就呈现 hung 死状态,什么也做不了

原理
在每一个 cpu 上有一个变量 hrtimer_interrupts, 这个变量会在 watchdog timer 中断的时候加 1,如果发现某个 cpu 上这个变量的值长时间没有增加,就说明发生了hardlock

1.1.1 检查 hrtimer_interrupts 变量2种方法

  • 每个 cpu 会有一个 NMI 中断(Non-maskable Interrupt),因为是 NMI 中断,所以即使 cpu 上禁止了中断,这个 NMI 中断也会发生。在中断处理函数中会检查自己这个 cpu 上 hrtimer_interrupts 的值是否增加。这种方法在 arm 中没有采用。
  • 每个cpu 会在 watchdog timer 中断中检查下一个 cpu 的 hrtimer_interrupts 的值(因为下一个 cpu 已经禁止中断,它自己的 watchdog timer callback无法被调用,所以只能靠别的 cpu 去检查。例如 cpu8 检查 cpu9, cpu9 检查 cpu0。如果下一个 cpu不在线,会检查再下一个 cpu。

1.1.2 hard lockup 测试例子

在下面例子中,中断被关闭,普通中断无法被相应(包括时钟中断),线程无法被调度,在这种情况下,不仅仅[watchdog/x]线程也无法工作,hrtimer 也无法被相应。

static DEFINE_SPINLOCK(test_lock);
static int hard_lockup_thread(void *data)
{    
    unsigned long flags;

    spin_lock_irqsave(&test_lock, flags);
    while (1);

    /* unreached */
    return 0;
}

然后过会就会打印如下log:

...
[60.624324] NMI watchdog: Watchdog detected hard LOCKUP on cpu 0    
...

上篇文章:ARM Linux 系统稳定性分析入门及渐进 1 – Crash 工具简介
下篇文章:ARM Linux 系统稳定性分析入门及渐进 3 – 栈溢出


在这里插入图片描述

推荐阅读:
https://editor.csdn.net/md/?articleId=128133753
https://editor.csdn.net/md/?articleId=128133753

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

主公CodingCos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值