linux的睡眠.docx
《linux的睡眠.docx》由会员分享,可在线阅读,更多相关《linux的睡眠.docx(21页珍藏版)》请在冰豆网上搜索。
![linux的睡眠.docx](https://file1.bdocx.com/fileroot1/2022-10/11/ec8e3c96-6318-459c-91bf-7ccb88e57f0e/ec8e3c96-6318-459c-91bf-7ccb88e57f0e1.gif)
linux的睡眠
这篇报告旨在弄清楚在x86平台下,睡眠的过程中,设备的行为是什么,特别时pcie设备,以及与ACPI有什么关系。
Linux内核提供了三种Suspend:
Freeze、Standby和STR(SuspendtoRAM),在用户空间向”/sys/power/state”文件分别写入”freeze”、”standby”和”mem”,即可触发它们。
这个报告涉及到的主要是STR(SuspendtoRAM)。
在用户空间执行如下操作:
echo"mem">/sys/power/state
然后内核中会进入在kernel/power/suspend.c定义的pm_suspend,处理所有的suspend过程。
intpm_suspend(suspend_state_tstate)
{
interror;
if(state<=PM_SUSPEND_ON||state>=PM_SUSPEND_MAX)
return-EINVAL;
error=enter_state(state);
if(error){
suspend_stats.fail++;
dpm_save_failed_errno(error);
}else{
suspend_stats.success++;
}
returnerror;
}
EXPORT_SYMBOL(pm_suspend);
enter_state代码为:
staticintenter_state(suspend_state_tstate)
{
interror;
trace_suspend_resume(TPS("suspend_enter"),state,true);
if(state==PM_SUSPEND_FREEZE){
#ifdefCONFIG_PM_DEBUG
if(pm_test_level!
=TEST_NONE&&pm_test_level<=TEST_CPUS){
pr_warning("PM:
Unsupportedtestmodeforsuspendtoidle,"
"pleasechoosenone/freezer/devices/platform.\n");
return-EAGAIN;
}
#endif
}elseif(!
valid_state(state)){//判断该平台是否支持该电源状态
return-EINVAL;
}
if(!
mutex_trylock(&pm_mutex))
return-EBUSY;
if(state==PM_SUSPEND_FREEZE)
freeze_begin();
#ifndefCONFIG_SUSPEND_SKIP_SYNC
trace_suspend_resume(TPS("sync_filesystems"),0,true);
printk(KERN_INFO"PM:
Syncingfilesystems...");
sys_sync();//文件系统同步
printk("done.\n");
trace_suspend_resume(TPS("sync_filesystems"),0,false);
#endif
pr_debug("PM:
Preparingsystemforsleep(%s)\n",pm_states[state]);
pm_suspend_clear_flags();
error=suspend_prepare(state);进行suspend前准备,主要是切换console,冻结线程和进程。
if(error)
gotoUnlock;
if(suspend_test(TEST_FREEZER))
gotoFinish;
trace_suspend_resume(TPS("suspend_enter"),state,false);
pr_debug("PM:
Suspendingsystem(%s)\n",pm_states[state]);
pm_restrict_gfp_mask();
error=suspend_devices_and_enter(state);这个接口就是负责挂起和恢复的所有实际的动作,过程相对复杂。
pm_restore_gfp_mask();
Finish:
pr_debug("PM:
Finishingwakeup.\n");
suspend_finish();
Unlock:
mutex_unlock(&pm_mutex);
returnerror;
}
suspend_devices_and_enter,kernel/power/suspend.c
intsuspend_devices_and_enter(suspend_state_tstate)
{
interror;
boolwakeup=false;
if(!
sleep_state_supported(state))
return-ENOSYS;
error=platform_suspend_begin(state);//调用suspend_ops的begin回调(有的话),通知平台代码,以便让其作相应的处理(需要的话)。
可能失败,需要跳至Close处执行恢复操作(suspend_ops->end)。
if(error)
gotoClose;
suspend_console();
suspend_test_start();
error=dpm_suspend_start(PMSG_SUSPEND);这个函数就是设备相关的电源管理的代码
if(error){
pr_err("PM:
Somedevicesfailedtosuspend,orearlywakeeventdetected\n");
gotoRecover_platform;
}
suspend_test_finish("suspenddevices");
if(suspend_test(TEST_DEVICES))
gotoRecover_platform;
do{
error=suspend_enter(state,&wakeup);
}while(!
error&&!
wakeup&&platform_suspend_again(state));
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resumedevices");
trace_suspend_resume(TPS("resume_console"),state,true);
resume_console();
trace_suspend_resume(TPS("resume_console"),state,false);
Close:
platform_resume_end(state);
returnerror;
Recover_platform:
platform_recover(state);
gotoResume_devices;
}
do{
error=suspend_enter(state,&wakeup);
}while(!
error&&!
wakeup&&platform_suspend_again(state));
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resumedevices");
trace_suspend_resume(TPS("resume_console"),state,true);
resume_console();
trace_suspend_resume(TPS("resume_console"),state,false);
Close:
platform_resume_end(state);
returnerror;
Recover_platform:
platform_recover(state);
gotoResume_devices;
}
dpm_suspend_start,drivers/base/power/main.c
intdpm_suspend_start(pm_message_tstate)
{
interror;
error=dpm_prepare(state);//设备在suspend之前需要做的一些工作,与下面的dpm_suspend(state)处理流程类似,所以以下面的dpm_suspend(state)做具体分析。
if(error){
suspend_stats.failed_prepare++;
dpm_save_failed_step(SUSPEND_PREPARE);
}else
error=dpm_suspend(state);
returnerror;
}
EXPORT_SYMBOL_GPL(dpm_suspend_start);
dpm_suspend,drivers/base/power/main.c
intdpm_suspend(pm_message_tstate)
{
ktime_tstarttime=ktime_get();
interror=0;
trace_suspend_resume(TPS("dpm_suspend"),state.event,true);
might_sleep();
cpufreq_suspend();
mutex_lock(&dpm_list_mtx);
pm_transition=state;
async_error=0;
while(!
list_empty(&dpm_prepared_list)){
structdevice*dev=to_device(dpm_prepared_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
error=device_suspend(dev);//对所有在dpm_list链表中的设备执行
mutex_lock(&dpm_list_mtx);
if(error){
pm_dev_err(dev,state,"",error);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
}
if(!
list_empty(&dev->power.entry))
list_move(&dev->power.entry,&dpm_suspended_list);
put_device(dev);
if(async_error)
b