[Kernel_exception6] MTK hang_detect

一、hang_detect介绍:

  MTK平台存在一个hang_detect的机制,用于检查应用层和驱动是否有卡住,应用层的system_server进程会

30s喂狗,也就是对kernel driver中的watchdog节点进行kick的操作,当kernel 里面的watchdog线程卡住时,或者

应用层发生SWT时不能及时喂狗,都会出现hang_detect的问题,出现问题时会有一定的等待时间重启,不同的

等待时间具有不同的意义:

  1. 正常情况下,watchdog thread tick 300s, 对应count=10.
  2. watchdog 检测到hang 30s, 在dump backtrace 前,tick 360s, 对应count=12.
  3. 在SWT 发生的情况下,tick 420s, 对应count=14.
  4. 在SWT 发生, 抓取完AEE DB 后, tick 330s, 对应count=11.
  5. 在 Surfaceflinger/SystemServer 发生Native Exception, tick 600s, 对应count=20.
  6. 在 Surfaceflinger/SystemServer 发生Native Exception后, 并且我司AEE开始抓取coredump, tick 1200s, 对应count=40.
  7. 在 Surfaceflinger/SystemServer 发生Native Exception, 并且我司AEE抓取完coredump后, tick 570, 对应count=19.

二、具体问题分析:

  下面来看实际项目中遇到的一个问题,通过如下log可以看出发生了hang_detect重启,并且重启的count=10,

说明问题可能发生在重启前的300S:

[  451.448876]  (0)[142:hang_detect][Hang_Detect] hang_detect thread counts down -1:10, status 1.    
[  453.277108] -(0)[142:hang_detect]PC is at hang_detect_thread+0x244/0x3a4
[  453.277126] -(0)[142:hang_detect]LR is at console_unlock+0x25c/0x4d8
[  453.277142] -(0)[142:hang_detect]pc : [<c06c8bbc>]    lr : [<c017a7b0>]    psr: 200b0113

  这时查看DB文件中的SYS_HANG_DETECT_RAW文件中watchdog的状态,可以看到很多进程挂在了__refrigerator

函数中,其中D状态是不可中断的睡眠状态,这一点可以查询进程的状态切换的相关知识。

watchdog        D 3.505309 927 7 6 0x800
<c0a6c9b4> __schedule+0x364/0x7a4
<c0a6ce2c> schedule+0x38/0x84
<c0188de8> __refrigerator+0xa0/0x188
<c01a1d1c> futex_wait_queue_me+0x178/0x17c
<c01a26b4> futex_wait+0x118/0x264
<c01a4224> do_futex+0x120/0xb70
<c01a4d04> SyS_futex+0x90/0x1a8
<ffffffff> 0xffffffff
......
main            D 1234.788544 874 29 608 0x1
<c0a6c9b4> __schedule+0x364/0x7a4
<c0a6ce2c> schedule+0x38/0x84
<c0188de8> __refrigerator+0xa0/0x188
<c0135e8c> get_signal+0x67c/0x680
<c010c7ec> do_signal+0x7c/0x500
<c010ce5c> do_work_pending+0xb8/0xc8

通过进程挂在了__refrigerator函数中,可以得知,问题可能在suspend的流程中挂住,由以下信息可以推断,

所有冻结的进程会系统调用到__refrigerator:

到这里,查看system_server,看到正好处于pm_suspend流程中,可以看到,system_server进程的处于可

中断的睡眠状态,其中调用函数挂在了xxx_suspend中:

system_server   S 97.000000 682 228 34 0x800
<c0a6c9b4> __schedule+0x364/0x7a4
<c0a6ce2c> schedule+0x38/0x84
<c0a6ff40> schedule_timeout+0x1e8/0x228
<c0a6f07c> __down_interruptible+0x90/0xf8
<c0171554> down_interruptible+0x54/0x60
<c04bffdc> xxx_suspend+0x58/0xd8
<c07842a4> i2c_device_pm_suspend+0x68/0x74
<c0457818> dpm_run_callback+0x64/0x1c8
<c0458804> __device_suspend+0x114/0x39c
<c045a7a8> dpm_suspend+0xb0/0x3a4
<c045affc> dpm_suspend_start+0x5c/0x60
<c0175a90> suspend_devices_and_enter+0xb4/0x314
<c01762b4> pm_suspend+0x4c4/0x6d0
<c01745e4> state_store+0x88/0xb0
<c03ef47c> kobj_attr_store+0x1c/0x28
<c02b57a4> sysfs_kf_write+0x48/0x4c
<c02b4fb0> kernfs_fop_write+0x134/0x1b8
<c0242a28> vfs_write+0xa8/0x1ec
<c0243094> SyS_write+0x54/0xb4

这时需要去看xxx_suspend函数:

static struct semaphore s_tSemaProtect;
static int xxx_mutex_lock(void)
{
	if (down_interruptible(&s_tSemaProtect))
			return (-ERESTARTSYS);
	return 0;
}

static void xxx_mutex_unlock(void)
{
	up(&s_tSemaProtect);
}

static int xxx_suspend(struct i2c_client *client, pm_message_t msg)  
{
	if(msg.event == PM_EVENT_SUSPEND)
	{   
		atomic_set(&obj->suspend, 1);
        xxx_mutex_lock();
		err = xxx_setPowerMode(client, false);
        xxx_mutex_unlock();  
	}
	return err;
}

  从上面的代码中,可以看到在xxx_suspend中确实去拿s_tSemaProtect信号量,我们知道,当线程去拿信号量时,

如果不能够及时获得会进入可中断的睡眠状态,这里就可以解释上面system_server处于S状态的现象。但可中断的

睡眠状态为何会导致hang_detect呢?这里需要进一步的去看s_tSemaProtect信号量的调用,可以通过GDB看此信号量

的信息如下,count = 0此时信号量不能被拿到:

这时怀疑有地方拿到了此信号量被其他地方拿住没有释放,所以继续看信号量的调用,发现如下:

static int xxx_resume(struct i2c_client *client)
{
    xxx_mutex_lock();	
    err = xxx_chip_resume(obj->client);
    if(err) {
        MI_ERR("chip resume fail!!\n");
        //xxx_mutex_unlock(); //缺少这个释放锁的操作
        return err;
    }
    err = xxx_setPowerMode(obj->client, true);
    xxx_mutex_unlock();

	atomic_set(&obj->suspend, 0);

	return 0;
}

  可以发现,在xxx_resume函数中,会获取硬件xxx_chip_resume的chip信息,当获取fail时会直接return error,

没有去做xxx_mutex_unlock的操作,导致信号一直没有被释放,这时去对应的kernel log再次验证问题:

[   94.647859]  (0)[682:system_server]Do softreset failed !
[   94.647871]  (0)[682:system_server] chip resume fail!!

  解决方法是在出错时也要及时的释放信号量,这样此模块出现问题时,不会导致心痛hang住。

  从此问题可以看出在问题的异常处理机制也需要做到完善,才能保证软件的正常运行。

作者:frank_zyp 
您的支持是对博主最大的鼓励,感谢您的认真阅读。 
本文无所谓版权,欢迎转载。

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/88978638
MTK