JB上手机睡眠时,遇到如下log,手机一直不能睡眠。
<3>[ 105.350862] Freezing of tasks failed after 20.02 seconds (1 tasks refusing to freeze, wq_busy=0):
<6>[ 105.350984] swapper/0 S c07da1b8 6404 117 1 0x00000000
<4>[ 105.351167] [<c07da1b8>] (__schedule+0x564/0x648) from [<c07da420>] (schedule+0x84/0x88)
<4>[ 105.351258] [<c07da420>] (schedule+0x84/0x88) from [<c07d7d0c>] (schedule_timeout+0x30/0x34c)
<4>[ 105.351319] [<c07d7d0c>] (schedule_timeout+0x30/0x34c) from [<c07d9928>] (__down_interruptible+0x7c/0xe0)
<4>[ 105.351411] [<c07d9928>] (__down_interruptible+0x7c/0xe0) from [<c009c994>] (down_interruptible+0x38/0x50)
<4>[ 105.351503] [<c009c994>] (down_interruptible+0x38/0x50) from [<c05a2098>] (GpioIST+0x68/0x1f4)
<4>[ 105.351594] [<c05a2098>] (GpioIST+0x68/0x1f4) from [<c000f6a8>] (kernel_thread_exit+0x0/0x8)
这个log显示出来,有一个进程拒绝睡眠,而且打印出来了相关栈信息,经过查看代码,定位到down_interruptible函数。
在down_interruptible中,会将进程状态设置为TASK_INTERRUPTIBLE,而处于 TASK_INTERRUPTIBLE状态的进程如果收到信号会被唤醒并处理信号,目前一个是中断中会调用up来唤醒,一个是通过睡眠流程中的freeze_task。
查看了ICS的睡眠流程:在休眠过程的第一步,需要调用函数freeze_processes()(定义在kernel/power/process.c)。此函数通过try_to_freeze_tasks()函数将所有“可冷冻”任务的TIF_FREEZE标志置位。如果这些任务是内核线程,则唤醒它们。如果是用户空间进程,则向它们发送一个欺骗信号[fake signals]。如果一个任务设置了TIF_FREEZE标志,就必须通过函数refrigerator()(定义在kernel/power /process.c)对其进行响应,这个函数设置任务的PF_FROZEN标志,将任务的状态切换至TASK_UNINTERRUPTIBLE,并且使得该任务不断的循环直到PF_FROZEN标准被清除。随后,我们就可以说这个任务被“冷冻”了,实现这个机制的那些函数则被称作“冰箱”(这些函数定义在kernel/power/process.c以及头文件include/linux/freezer.h)。用户空间进程需在内核线程之前被逐个地冷冻。
而且目前代码的框架和linux文档中描述的是一样的:
set_freezable();/*可以冻结*/
set_user_nice(current, -19);/*设置优先级,很高*/
while(1){
retval = down_interruptible(g_lptsGpioRxEvent);/*平时会hold在这里*/
...
if(retval )
try_to_freeze();
}
查看了JB的睡眠流程:发现没有ICS将进程状态置为TIF_FREEZE的操作,而是使用system_freezing_cnt表示系统是否接受睡眠操作。所以现在的睡眠流程不能唤醒使用接口down_interruptible的进程,最后使用wait_event_freezable后解决该问题。