电源管理基本观念之一
来源:互联网 发布:生气 知乎 编辑:程序博客网 时间:2024/05/22 09:45
1.Linux 描述的电源状态
- On(on)
- Standby (standby)
- Suspend to RAM(mem) S3 - RAM is powered and the running content is saved to RAM
- Suspend to Disk,Hibernation(disk) S4 -
S3 aka STR(suspend to ram),挂起到内存,简称待机。计算机将目前的运行状态等数据存放在内存,关闭硬盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少。恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。对DDR的耗电情况进行优化是S3性能的关键,大多数手持设备都是用S3待机。
S4 aka STD(suspend to disk),挂起到硬盘,简称休眠。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。电子书项目中,见过一款索尼的电子书,没有定义关机状态,只定义了S4,从而提高开机速度。
2.Linux内核电源管理接口
static int __init pm_init(void){int error = pm_start_workqueue();if (error)return error;hibernate_image_size_init();hibernate_reserved_size_init();power_kobj = kobject_create_and_add("power", NULL);if (!power_kobj)return -ENOMEM;error = sysfs_create_group(power_kobj, &attr_group);if (error)return error;return pm_autosleep_init();}
static struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,&pm_trace_dev_match_attr.attr,#endif#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,&wakeup_count_attr.attr,#ifdef CONFIG_PM_AUTOSLEEP&autosleep_attr.attr,#endif#ifdef CONFIG_PM_WAKELOCKS&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif#endifNULL,};static struct attribute_group attr_group = {.attrs = g,};从代码可以看出来,state属性是主属性文件,必须具备,其他属性文件都有相应的宏开关,根据需要定制。
3. 电源状态切换(state属性文件)
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n){suspend_state_t state;int error;error = pm_autosleep_lock();if (error)return error;if (pm_autosleep_state() > PM_SUSPEND_ON) {error = -EBUSY;goto out;}state = decode_state(buf, n);if (state < PM_SUSPEND_MAX)error = pm_suspend(state);else if (state == PM_SUSPEND_MAX)error = hibernate();elseerror = -EINVAL; out:pm_autosleep_unlock();return error ? error : n;}autosleep是android内核为了跟主线内核兼容所引入的。切换电源状态的入口函数是pm_suspend。针对嵌入式系统,S3是一种比较常用的节电状态。俗称待机。待机过程可以粗略的分为五个阶段,但不一定有严格的界限。
b)挂起设备
c)针对soc相应的节电操作和为唤醒做准备工作
d)smp中非启动cpu的挂起
e)cpu core的挂起
3.1 冻结用户进程
进程冻结模块由CONFIG_FREEZER宏开关控制。
相关代码在kernel/power/process.c中,程序的结构比较简洁,总共就五个函数。
freeze process的控制过程都在freeze_processes函数中
int freeze_processes(void){int error;error = __usermodehelper_disable(UMH_FREEZING);if (error)return error;if (!pm_freezing)atomic_inc(&system_freezing_cnt);printk("Freezing user space processes ... ");pm_freezing = true;error = try_to_freeze_tasks(true);if (!error) {printk("done.");__usermodehelper_set_disable_depth(UMH_DISABLED);oom_killer_disable();}printk("\n");BUG_ON(in_atomic());if (error)thaw_processes();return error;}
进程的冻结控制过程如下:
1. 冻结khelper内核线程。khelper是一个用于从内核空间调用用户空间应用程序的内核模块。能够在动态加载模块,热插拔等场景中发挥作用。
2.调用try_to_freeze_tasks冻结task_struct表中的任务。
3.如果try_to_freeze_tasks没有返回error则disable usermode helper 和 oom killer并成功返回。
4.如果try_to_freeze_tasks返回error则调用thaw_processes解冻操作。
try_to_freeze_tasks和thaw_process是一对反函数。冻结进程的工作是在两个循环中完成的。冻结进程要访问task_struct列表,所以先要加锁,然后用do_each_thread(g, p) 和while_each_thread(g, p)循环改变task_struct列表中进程的状态。把两个宏展开后的代码如下:
/×for循环从init_task(idle process)开始遍历所有进程×/for (g = p = &init_task ; (g = p = next_task(g)) != &init_task ; ) do{/×如果是当前进程或者freeze_task失败则回到for循环开始下一个进程×/if (p == current || !freeze_task(p))continue;/×如果进程是stop或者应该跳过的进程则标记todo++,后面会专门针对这类进程重新处理×/if (!task_is_stopped_or_traced(p) && !freezer_should_skip(p))todo++;}while ((p = next_thread(p)) != g)//while循环则从主线程开始遍历每个进程的所有线程
3.2 挂起设备(Device Power Manager)
struct dev_pm_ops {int (*prepare)(struct device *dev);void (*complete)(struct device *dev);int (*suspend)(struct device *dev);int (*resume)(struct device *dev);int (*freeze)(struct device *dev);int (*thaw)(struct device *dev);int (*poweroff)(struct device *dev);int (*restore)(struct device *dev);int (*suspend_late)(struct device *dev);int (*resume_early)(struct device *dev);int (*freeze_late)(struct device *dev);int (*thaw_early)(struct device *dev);int (*poweroff_late)(struct device *dev);int (*restore_early)(struct device *dev);int (*suspend_noirq)(struct device *dev);int (*resume_noirq)(struct device *dev);int (*freeze_noirq)(struct device *dev);int (*thaw_noirq)(struct device *dev);int (*poweroff_noirq)(struct device *dev);int (*restore_noirq)(struct device *dev);int (*runtime_suspend)(struct device *dev);int (*runtime_resume)(struct device *dev);int (*runtime_idle)(struct device *dev);};每个函数的应用场景都有专门的注释说明,详细的说明也在include/linux/pm.h文件中。针对设备电源管理的代码在driver/base/power/main.c文件中。电源管理相关的操作紧密的跟设备模型结合在一起。
struct dev_pm_infopower;struct dev_pm_domain*pm_domain;DPM则利用dev_pm_info结构体的power->entry成员和dev_pm_domain结构体的dev_pm_domain成员把参入系统电源管理的设备以及相关的操作串联起来的。下面是一个简单的数据流程:
device suspend由suspend模块完成,suspend模块由CONFIG_SUSPEND宏开关控制
obj-$(CONFIG_SUSPEND)+= suspend.o代码就在kernel/power/suspend.c中
suspend模块对外导出了pm_suspend接口:
/** * pm_suspend - Externally visible function for suspending the system. * @state: System sleep state to enter. * * Check if the value of @state represents one of the supported states, * execute enter_state() and update system suspend statistics. */int pm_suspend(suspend_state_t state){int error;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++;}return error;}EXPORT_SYMBOL(pm_suspend);
pm_suspend被用来控制系统的设备进入指定的状态。前面提到的Linux定义的四种电源状态会被传递到这个函数,pm_suspend会对电源状态做检查,如果传入的是非法之,直接返回EINVAL。
四种电源状态定在include/linux/suspend.h文件中
typedef int __bitwise suspend_state_t;#define PM_SUSPEND_ON((__force suspend_state_t) 0)#define PM_SUSPEND_STANDBY((__force suspend_state_t) 1)#define PM_SUSPEND_MEM((__force suspend_state_t) 3)#define PM_SUSPEND_MAX((__force suspend_state_t) 4)
针对具体设备休眠的操作都在针对设备休眠的驱动里面。相关的文件在driver/base/power/目录下。针对设备的休眠动作在driver/base/power/main.c文件中。该文件对外导出了三个接口,suspend模块用到了这些接口。
/** * dpm_suspend_start - Prepare devices for PM transition and suspend them. * @state: PM transition of the system being carried out. * * Prepare all non-sysdev devices for system PM transition and execute "suspend" * callbacks for them. */int dpm_suspend_start(pm_message_t state){int error;error = dpm_prepare(state);if (error) {suspend_stats.failed_prepare++;dpm_save_failed_step(SUSPEND_PREPARE);} elseerror = dpm_suspend(state);return error;}EXPORT_SYMBOL_GPL(dpm_suspend_start);void __suspend_report_result(const char *function, void *fn, int ret){if (ret)printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);}EXPORT_SYMBOL_GPL(__suspend_report_result);/** * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete. * @dev: Device to wait for. * @subordinate: Device that needs to wait for @dev. */int device_pm_wait_for_dev(struct device *subordinate, struct device *dev){dpm_wait(dev, subordinate->power.async_suspend);return async_error;}EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
3.3 平台相关挂起操作(platform suspending)
在设备挂起操作完成之后,会针对特定平台做状态转换操作。Linux内核电源管理模块也为此定义了一组标准函数接口。不同架构只需要实现相应接口即可。struct platform_suspend_ops {int (*valid)(suspend_state_t state);int (*begin)(suspend_state_t state);int (*prepare)(void);int (*prepare_late)(void);int (*enter)(suspend_state_t state);void (*wake)(void);void (*finish)(void);bool (*suspend_again)(void);void (*end)(void);void (*recover)(void);};
这组函数功能如下:
- 电源管理基本观念之一
- 电源管理基本观念之一
- 电源管理基本观念之一
- 电源管理基本观念之一
- 电源管理基本观念之二
- 电源管理基本观念之二
- 电源管理基本观念之二
- 【转】Windows CE的电源管理之一
- Windows CE的电源管理之一
- Windows CE的电源管理之一
- Android电源管理之一:基础概览
- Android电源管理之一:基础概览
- Android7.0 电源管理-updatePowerStateLocked 基本流程图
- 软件工程基本观念
- 第一章 软件工程基本观念
- Linux Kernel基本观念
- 电源管理
- 电源管理
- Hadoop学习笔记-Hadoop在Windows下安装
- C#入门经典(第五版)
- jquery对象和dom对象相互转换
- 经济管理、销售、人资
- ajaxFileUpload 导致框架混乱
- 电源管理基本观念之一
- hadoop 在windows的Eclipse下运行出现Cannot run program "chmod": CreateProcess error=2 异常
- java中断点调试的几个快捷键
- ASP.NET访问网络驱动器(映射磁盘)
- iOS小整合
- Caused by: org.xml.sax.SAXParseException
- JAVA利用反射调用函数的时间
- jQuery获取form表单元素值 总结
- 第12讲 ip地址和包路由详解 网络环境配置