首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

linux电源管理更新

linux电源管理更新

3.1冻结用户进程进程冻结模块由CONFIG_FREEZER宏开关控制。
相关代码在kernel/power/process.c中,程序的结构比较简洁,总共就五个函数。

freezeprocess的控制过程都在freeze_processes函数中

[plain] view plaincopyprint?

  • 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则disableusermode 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列表中进程的状态。把两个宏展开后的代码如下:
[cpp] view plaincopyprint?

  • 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)

设备电源的管理涉及到两种不同的场景:一种是在系统电源状态发生转变的情况下,譬如从S0->S3或者S0->S4。另外一种是在系统处在S0,但是仍然有些不被使用的设备进入节电的状态,这种情况就是runtimedevice manager,对应在手持设备上,直接影响所谓的场景功耗。设备电源管理,同时涉及到器件,总线,控制器,子系统,同类设备的状态改变,对于操作的顺序上有一定的要求。举个例子,一条i2c总线上挂有camera,gensor,lighter sensor,那么i2c总线控制器必须要确保总线上的设备先进入lowpower或者off状态才能进入节电模式,因为Linux的驱动模型把总线和设备是分开控制的。另外许多设备都能作为系统的唤醒源,这个要求也要纳入统一的考虑。Linux2.5及以后的内核引入设备模型,把总线,设备,子设备,同一类型设备,子系统通过kobject组织起来,为devicepower manager提供了统一的控制平台。


通常情况下,设备进入suspend状态,通常都会I/O口停止工作,DAM停止工作,也不会请求中断,停止数据的读写传输。但是如果设备作为唤醒源,则依然为出发中断控制器的中断信号线。对于设备的管理,Linux在DPM(dynamicpowermanager)的架构下,提供了一整套机制,可以灵活的针对不同特性的设备。在include/linux/pm.h文件中定义了一组回调函数指针用于各种情况:
[cpp] view plaincopyprint?

  • 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文件中。电源管理相关的操作紧密的跟设备模型结合在一起。

device结构体中有两个与电源管理关系密切的成员:
[cpp] view plaincopyprint?

  • struct dev_pm_info  power;  
  • struct dev_pm_domain    *pm_domain;  

DPM则利用dev_pm_info结构体的power->entry成员和dev_pm_domain结构体的dev_pm_domain成员把参入系统电源管理的设备以及相关的操作串联起来的。下面是一个简单的数据流程:


返回列表