linux待机流程,Linux睡眠喚醒機制--Kernel態

一、對於休眠(suspend)的簡單介紹   在Linux中,休眠主要分三個主要的步驟:   1) 凍結用戶態進程和內核態任務

2) 調用注冊的設備的suspend的回調函數, 順序是按照注冊順序

3) 休眠核心設備和使CPU進入休眠態, 凍結進程是內核把進程列表中所有的進程的狀態都設置為停止,並且保存下所有進程的上下文. 當這些進程被解凍的時候,他們是不知道自己被凍結過的,只是簡單的繼續執行。

如何讓Linux進入休眠呢?用戶可以通過讀寫sys文件/sys /power/state 是實現控制系統進入休眠. 比如

# echo mem > /sys/power/state

命令系統進入休眠. 也可以使用

# cat /sys/power/state

來得到內核支持哪幾種休眠方式.

二、Linux Suspend 的流程1. 相關代碼

• kernel/kernel/power/main.c

• kernel/arch/arm/mach-xxx/pm.c

• kernel/driver/base/power/main.c

接下來讓我們詳細的看一下Linux是怎么休眠/喚醒的:

用戶對於/sys/power/state 的讀寫會調用到 kernel/kernel/power/main.c中的state_store(), 用戶可以寫入 const char * const pm_states[] 中定義的字符串, 比如"mem", "standby"。

const char *const pm_states[PM_SUSPEND_MAX] = {

#ifdef CONFIG_EARLYSUSPEND

[PM_SUSPEND_ON]  = "on",

#endif

[PM_SUSPEND_STANDBY] = "standby",

[PM_SUSPEND_MEM] = "mem",

};

常見有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗電更多,返回到正常工作狀態的時間更短。

然后state_store()會調用enter_state(),它首先會檢查一些狀態參數,然后同步文件系統。/**

*  enter_state - Do common work of entering low-power state.

*  @state:     pm_state structure for state we're entering.

*

*  Make sure we're the only ones trying to enter a sleep state. Fail

*  if someone has beat us to it, since we don't want anything weird to

*  happen when we wake up.

*  Then, do the setup for suspend, enter the state, and cleaup (after

*  we've woken up).

*/

intenter_state(suspend_state_t state)

{

interror;

if(!valid_state(state))

return-ENODEV;

if(!mutex_trylock(&pm_mutex))

return-EBUSY;

#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE

suspend_sys_sync_queue();

#else

printk(KERN_INFO "PM: Syncing filesystems ... ");

sys_sync();

printk("done.\n");

#endif

pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);

error = suspend_prepare();

if(error)

gotoUnlock;

if(suspend_test(TEST_FREEZER))

gotoFinish;

pr_debug("PM: Entering %s sleep\n", pm_states[state]);

pm_restrict_gfp_mask();

error = suspend_devices_and_enter(state);

pm_restore_gfp_mask();

Finish:

pr_debug("PM: Finishing wakeup.\n");

suspend_finish();

Unlock:

mutex_unlock(&pm_mutex);

returnerror;

}

2. 准備, 凍結進程       當進入到suspend_prepare()中以后, 它會給suspend分配一個虛擬終端來輸出信息, 然后廣播一個系統要進入suspend的Notify, 關閉掉用戶態的helper進程, 然后一次調用suspend_freeze_processes()凍結所有的進程, 這里會保存所有進程當前的狀態, 也許有一些進程會拒絕進入凍結狀態, 當有這樣的進程存在的時候, 會導致凍結失敗,此函數就會放棄凍結進程,並且解凍剛才凍結的所有進程。

/**

*  suspend_prepare - Do prep work before entering low-power state.

*

*  This is common code that is called for each state that we're entering.

*  Run suspend notifiers, allocate a console and stop all processes.

*/

staticintsuspend_prepare(void)

{

interror;

if(!suspend_ops || !suspend_ops->enter)

return-EPERM;

pm_prepare_console();

error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);

if(error)

gotoFinish;

error = usermodehelper_disable();

if(error)

gotoFinish;

error = suspend_freeze_processes();

if(!error)

return0;

suspend_thaw_processes();

usermodehelper_enable();

Finish:

pm_notifier_call_chain(PM_POST_SUSPEND);

pm_restore_console();

returnerror;

}

3. 讓外設進入休眠        現在, 所有的進程(也包括workqueue/kthread) 都已經停止了,內核態人物有可能在停止的時候握有一些信號量, 所以如果這時候在外設里面去解鎖這個信號量有可能會發生死鎖,所以在外設的suspend()函數里面作lock/unlock鎖要非常小心,這里建議設計的時候就不要在suspend()里面等待鎖。而且因為suspend的時候,有一些Log是無法輸出的,所以一旦出現問題,非常難調試。

然后kernel在這里會嘗試釋放一些內存。

最后會調用suspend_devices_and_enter()來把所有的外設休眠, 在這個函數中, 如果平台注冊了suspend_ops(通常是在板級定義中定義和注冊,在kernel/arch/arm/mach-xx/pm.c中調用suspend_set_ops), 這里就會調用 suspend_ops->begin(); 然后調用dpm_suspend_start,他們會依次調用驅動的suspend() 回調來休眠掉所有的設備。

當所有的設備休眠以后, suspend_ops->prepare()會被調用, 這個函數通常會作一些准備工作來讓板機進入休眠。 接下來Linux,在多核的CPU中的非啟動CPU會被關掉,通過注釋看到是避免這些其他的CPU造成race condio,接下來的以后只有一個CPU在運行了。

suspend_ops 是板級的電源管理操作, 通常注冊在文件 arch/arch/mach-xxx/pm.c 中.

接下來, suspend_enter()會被調用, 這個函數會關閉arch irq, 調用 device_power_down(), 它會調用suspend_late()函數, 這個函數是系統真正進入休眠最后調用的函數,通常會在這個函數中作最后的檢查。 如果檢查沒問題, 接下來休眠所有的系統設備和總線,並且調用 suspend_pos->enter() 來使CPU進入省電狀態,這時就已經休眠了。代碼的執行也就停在這里了。/**

*  suspend_devices_and_enter - suspend devices and enter the desired system

*                  sleep state.

*  @state:       state to enter

*/

intsuspend_devices_and_enter(suspend_state_t state)

{

interror;

if(!suspend_ops)

return-ENOSYS;

trace_machine_suspend(state);

// 如果平台注冊了suspend_ops(通常是在板級定義中定義和注冊,

// 在kernel/arch/arm/mach-xx/pm.c中調用suspend_set_ops),

// 這里就會調用 suspend_ops->begin();

if(suspend_ops->begin) {

error = suspend_ops->begin(state);

if(error)

gotoClose;

}

suspend_console();

suspend_test_start();

// 依次調用驅動的suspend() 回調來休眠掉所有的設備。

error = dpm_suspend_start(PMSG_SUSPEND);

if(error) {

printk(KERN_ERR "PM: Some devices failed to suspend\n");

gotoRecover_platform;

}

suspend_test_finish("suspend devices");

if(suspend_test(TEST_DEVICES))

gotoRecover_platform;

// 這個函數會關閉arch irq, 調用 device_power_down(), 它會調用suspend_late()函數,

// 這個函數是系統真正進入休眠最后調用的函數,通常會在這個函數中作最后的檢查。

// 如果檢查沒問題, 接下來休眠所有的系統設備和總線,並且調用 suspend_pos->enter()

// 來使CPU進入省電狀態,這時就已經休眠了。代碼的執行也就停在這里了。

error = suspend_enter(state);

Resume_devices:

suspend_test_start();

dpm_resume_end(PMSG_RESUME);

suspend_test_finish("resume devices");

resume_console();

Close:

if(suspend_ops->end)

suspend_ops->end();

trace_machine_suspend(PWR_EVENT_EXIT);

returnerror;

Recover_platform:

if(suspend_ops->recover)

suspend_ops->recover();

gotoResume_devices;

}

三、Linux Resume流程

如果在休眠中系統被中斷或者其他事件喚醒,接下來的代碼就會開始執行,這個喚醒的順序是和休眠的循序相反的,所以系統設備和總線會首先喚醒,使能系統中斷,使能休眠時候停止掉的非啟動CPU, 以及調用suspend_ops->finish(), 而且在suspend_devices_and_enter()函數中也會繼續喚醒每個設備,使能虛擬終端, 最后調用 suspend_ops->end()。

在返回到enter_state()函數中的,當 suspend_devices_and_enter() 返回以后,外設已經喚醒了,但是進程和任務都還是凍結狀態, 這里會調用suspend_finish()來解凍這些進程和任務, 而且發出Notify來表示系統已經從suspend狀態退出, 喚醒終端。

到這里,所有的休眠和喚醒就已經完畢了,系統繼續運行了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

strictmath_Java StrictMath log1p()方法与示例

strictmathStrictMath类log1p()方法 (StrictMath Class log1p() method) log1p() method is available in java.lang package. log1p()方法在java.lang包中可用。 log1p() method is used to return (the logarithm of the sum of the given argument and 1 like log(1d) in th…

第六章 抽象

第六章 抽象 自定义函数 要判断某个对象是否可调用,可使用内置函数callable import math x 1 y math.sqrt callable(x)#结果为:False callable(y)#结果为:True使用def(表示定义函数)语句,来定义函数 …

HTTP 状态代码

如果向您的服务器发出了某项请求要求显示您网站上的某个网页(例如,当用户通过浏览器访问您的网页或在 Googlebot 抓取该网页时),那么,您的服务器会返回 HTTP 状态代码以响应该请求。 此状态代码提供了有关请求状态的信…

TensorFlow的可训练变量和自动求导机制

文章目录一些概念、函数、用法TensorFlow实现一元线性回归TensorFlow实现多元线性回归一些概念、函数、用法 对象Variable 创建对象Variable: tf.Variable(initial_value,dtype)利用这个方法,默认整数为int32,浮点数为float32,…

linux samba安装失败,用aptitude安装samba失败

版本:You are using Ubuntu 10.04 LTS- the Lucid Lynx - released in April 2010 and supported until April 2013.root下执行aptitude install sambaReading package lists... DoneBuilding dependency treeReading state information... DoneReading extended st…

django第二个项目--使用模板做一个站点访问计数器

上一节讲述了django和第一个项目HelloWorld,这节我们讲述如何使用模板,并做一个简单的站点访问计数器。 1、建立模板 在myblog模块文件夹(即包含__init__.py的文件夹)下面新建一个文件夹templates,用于存放HTML模板,在…

strictmath_Java StrictMath log10()方法与示例

strictmathStrictMath类log10()方法 (StrictMath Class log10() method) log10() method is available in java.lang package. log10()方法在java.lang包中可用。 log10() method is used to return the logarithm of the given (base 10) of the given argument in the method…

30、深入理解计算机系统笔记,并发编程(concurrent)(2)

1、共享变量 1)线程存储模型 线程由内核自动调度,每个线程都有它自己的线程上下文(thread context),包括一个惟一的整数线程ID(Thread ID,TID),栈,栈指针,程序…

PostgreSQL在何处处理 sql查询之十三

继续: /*--------------------* grouping_planner* Perform planning steps related to grouping, aggregation, etc.* This primarily means adding top-level processing to the basic* query plan produced by query_planner.** tuple_fraction i…

【视觉项目】基于梯度的NCC模板匹配代码以及效果

文章目录流程分析工程代码【1】NCC代码【Ⅰ】sttPxGrdnt结构体【Ⅱ】sttTemplateModel模板结构体【Ⅲ】calcAccNCC计算ncc系数函数【Ⅳ】searchNcc NCC模板匹配函数【Ⅴ】searchSecondNcc 二级搜索:在某一特定点周围再以步进为1搜索【2】测试图转外轮廓【Ⅰ】孔洞填…

第七章 再谈抽象

第七章 再谈抽象 对象魔法 多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常运行。(即:无需知道对象的内部细节就可使用它)(无需知道对象所属的类(对象的类型)就能调用其…

c语言math乘法,JavaScript用Math.imul()方法进行整数相乘

1. 基本概念Math.imul()方法用于计算两个32位整数的乘积,它的结果也是32位的整数。JavaScript的Number类型同时包含了整数和浮点数,它没有专门的整型和浮点型。因此,Math.imul()方法能提供类似C语言的整数相乘的功能。我们将Math.imul()方法的…

java scanner_Java Scanner nextLong()方法与示例

java scanner扫描器类的nextLong()方法 (Scanner Class nextLong() method) Syntax: 句法: public long nextLong();public long nextLong(int rad);nextLong() method is available in java.util package. nextLong()方法在java.util包中可用。 nextLong() method…

技术总监和CTO的区别 浅谈CTO的作用----软件公司如何开源节流(一)

我一直在思考软件公司如何开源节流。当然,老板也在思考开源节流。当然,老板思考的开源节流在公司运营层面上,而我作为CTO,我考虑的则是在产品运营角度上来思考这个问题。否则,一个软件公司,它的生存与发展就…

梯度下降法预测波士顿房价以及简单的模型评估

目录原理代码关于归一化的思考原理 观察数据可知属性之间差距很大,为了平衡所有的属性对模型参数的影响,首先进行归一化处理。 每一行是一个记录,每一列是个属性,所以对每一列进行归一化。 二维数组归一化:1、循环方式…

Windows Phone 内容滑动切换实现

在新闻类的APP中,有一个经常使用的场景:左右滑动屏幕来切换上一条或下一条新闻。 那么通常我们该使用哪种方式去实现呢?可以参考一下Demo的实现步骤。 1,添加Windows Phone用户自定义控件。例如: 这里我为了演示的方便…

c语言interrupt函数,中断处理函数数组interrupt[]初始化

在系统初始化期间,trap_init()函数将对中断描述符表IDT进行第二次初始化(第一次只是建一张IDT表,让其指向ignore_intr函数),而在这次初始化期间,系统的0~19号中断(用于分NMI和异常的中断向量)均被设置好。与此同时,用于…

bytevalue_Java Number byteValue()方法与示例

bytevalueNumber类byteValue()方法 (Number Class byteValue() method) byteValue() method is available in java.lang package. byteValue()方法在java.lang包中可用。 byteValue() method is used to return the value denoted by this Number object converted to type byt…

第二章 染色热力学理论单元测验

1,()测定是染色热力学性能研究的基础 吸附等温线。 2,吸附是放热反应,温度升高,亲和力() 减小 3,染色系统中包括() 染料。 染深色介质。 染色助剂。 纤维。 4,下列对状态函数特点叙述正确的为() 状态函数只有在平衡状态的系统中才有确定值。 在非平衡状态的系统…

使用鸢尾花数据集实现一元逻辑回归、多分类问题

目录鸢尾花数据集逻辑回归原理【1】从线性回归到广义线性回归【2】逻辑回归【3】损失函数【4】总结TensorFlow实现一元逻辑回归多分类问题原理独热编码多分类的模型参数损失函数CCETensorFlow实现多分类问题独热编码计算准确率计算交叉熵损失函数使用花瓣长度、花瓣宽度将三种鸢…