前言

什么是Autosleep?   字面理解就是"没有事情干的时候睡觉"。而起初autosleep是在Android上的一个patch(https://lwn.net/Articles/479711/)演化而来的,当时名字叫做"Opportunistic sleep",翻译过来叫做"机会主义睡眠",也就是有机会就睡。因为此名字比较有争议,最后修改为autosleep。
autosleep一种强大的电源管理方法,只要在系统没有什么事情可做的时候,整个系统就睡眠下去。此机制在android手机上非常有效,同时也能阻止不良应用程序一直保持系统唤醒,浪费电池。但是重要的是:  如何判断当前系统没有事情可做,也就是如何判断系统在空闲状态? 
这时候wakeup event framework的出现就可以解决此问题,当系统中没有wakeup event事件的时候,就尝试系统suspend。如果在suspend的过程中有wakeup event就接着resume系统即可。
同样autosleep.c的注释可以说明autosleep的前生是Opportunistic sleep。
/** kernel/power/autosleep.c** Opportunistic sleep support.** Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>*/
详细文章可见:  https://lwn.net/Articles/479841/

Autosleep原理

1.  当系统没有任何事情做的时候,就尝试susupend。
2.  当系统中没有wakeup event事件发生的时候,就可以尝试suspend,需要wakeup event framework机制支持。
3.  autosleep功能需要在kernel config中开启CONFIG_PM_AUTOSLEEP=y。
4.  通过写"mem, disk,  standby, freeze"到/sys/power/autosleep可以开启autosleep。
5.  通过写"off"到/sys/power/autosleep就可以关闭autosleep。

流程分析

A:  通过执行"echo mem >  /sys/power/autosleep"此命令,系统就会在没有事情可做的时候,选择执行suspend的流程。
static ssize_t autosleep_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{suspend_state_t state = decode_state(buf, n);int error;if (state == PM_SUSPEND_ON&& strcmp(buf, "off") && strcmp(buf, "off\n"))return -EINVAL;error = pm_autosleep_set_state(state);return error ? error : n;
}

通过判断当前state的状态,如果是off的话,直接返回,否则调用pm_autosleep_set_state函数。

int pm_autosleep_set_state(suspend_state_t state)
{#ifndef CONFIG_HIBERNATIONif (state >= PM_SUSPEND_MAX)return -EINVAL;
#endif__pm_stay_awake(autosleep_ws);mutex_lock(&autosleep_lock);autosleep_state = state;__pm_relax(autosleep_ws);if (state > PM_SUSPEND_ON) {pm_wakep_autosleep_enabled(true);queue_up_suspend_work();} else {pm_wakep_autosleep_enabled(false);}mutex_unlock(&autosleep_lock);return 0;
}

1.  判断state参数是否合法。

2.  调用__pm_stay_awake上报一个wakeup events,保持系统唤醒。
3.  使用mutex保护全局变量autosleep。
4.  使用参数state,修改autosleep_state
5.  调用__pm_relax释放wakeup events,系统可以睡眠。
6.  判断state的值,如果是off,调用pm_wakep_autosleep_enabled函数disable autosleep,否则调用pm_wakep_autosleep_enabled函数enable autosleep功能,同时提交工作队列。
void pm_wakep_autosleep_enabled(bool set)
{struct wakeup_source *ws;ktime_t now = ktime_get();rcu_read_lock();list_for_each_entry_rcu(ws, &wakeup_sources, entry) {spin_lock_irq(&ws->lock);if (ws->autosleep_enabled != set) {ws->autosleep_enabled = set;if (ws->active) {if (set)ws->start_prevent_time = now;elseupdate_prevent_sleep_time(ws, now);}}spin_unlock_irq(&ws->lock);}rcu_read_unlock();
}

1.  对系统中的所有wakeup source,修改autosleep_enable标志。

2.  如果此wakeup状态是active,且autosleep为enable的话,修改wakeup source的start_prevenet_time修改为现在,意味着从现在开始就已经阻止autosleep的功能。
3.  如果此wakeup状态是active,且autosleep为disable的话。说明在此wakeup source active的过程中,关闭了autosleep功能,更新总的阻止autosleep的时间。
void queue_up_suspend_work(void)
{if (autosleep_state > PM_SUSPEND_ON)queue_work(autosleep_wq, &suspend_work);
}

此时就需要将suspend_work挂入到autosleep_wq工作队列中,而autosleep_wq是在函数pm_autosleep_init函数中创建的。

int __init pm_autosleep_init(void)
{autosleep_ws = wakeup_source_register("autosleep");if (!autosleep_ws)return -ENOMEM;autosleep_wq = alloc_ordered_workqueue("autosleep", 0);if (autosleep_wq)return 0;wakeup_source_unregister(autosleep_ws);return -ENOMEM;
}

1.  此函数会主次一个"autosleep" wakeupsource。用于在设置autosleep的状态时,保持系统处于唤醒状态。

2.  同时创建一个名字为"autosleep"的有序工作队列。为了保证一个时刻只能处理一个work。
B:  当提交suspend_work到工作队列之后,就会调用try_to_suspend函数查询是否可以进入suspend。
static void try_to_suspend(struct work_struct *work)
{unsigned int initial_count, final_count;if (!pm_get_wakeup_count(&initial_count, true))goto out;mutex_lock(&autosleep_lock);if (!pm_save_wakeup_count(initial_count) ||system_state != SYSTEM_RUNNING) {mutex_unlock(&autosleep_lock);goto out;}if (autosleep_state == PM_SUSPEND_ON) {mutex_unlock(&autosleep_lock);return;}if (autosleep_state >= PM_SUSPEND_MAX)hibernate();elsepm_suspend(autosleep_state);mutex_unlock(&autosleep_lock);if (!pm_get_wakeup_count(&final_count, false))goto out;/** If the wakeup occured for an unknown reason, wait to prevent the* system from trying to suspend and waking up in a tight loop.*/if (final_count == initial_count)schedule_timeout_uninterruptible(HZ / 2);out:queue_up_suspend_work();
}

1.  调用pm_get_wakeup_count函数获取系统的wakeup count数量,存放到initial_count变量中。

2.  调用pm_save_wakeup_count函数存放到saved_count变量中,如果失败,说明有wakeup event发生。跳到out处重新提交,重新来过。
3.  根据autosleep_state的状态,进行相应的睡眠方式。
4.  在系统产生wakeup event之后,唤醒系统之后再次读取wakeup count的数量。
5.  如果读取数量和suspend保存的一样,说明有不明原因唤醒系统。这时候就会发生:  autosleep->wakeup->autosleep->wakeup的循环中。所以此时try_to_suspend函数等待0.5s,再次尝试suspend。
C:  这时候系统就会在没事做的时候尝试suspend。
D:  如果有唤醒事件,系统就会从睡眠中唤醒。

Linux电源管理-Autosleep相关推荐

  1. Linux电源管理(10)_autosleep

    Linux电源管理(10)_autosleep 作者:wowo 发布于:2014-9-18 23:42 分类:电源管理子系统 1. 前言 Autosleep也是从Android wakelocks补丁 ...

  2. linux 电池管理软件,Linux电源管理(2)_Generic PM之基本概念和软件架构

    Linux电源管理(2)_Generic PM之基本概念和软件架构 作者:wowo 发布于:2014-5-13 19:24 分类:电源管理子系统 1. 前言 这里的Generic PM,是蜗蜗自己起的 ...

  3. linux 电源管理 Generic PM之Suspend功能

    Linux电源管理(6)_Generic PM之Suspend功能 作者:wowo 发布于:2014-8-22 21:40 分类:电源管理子系统 1. 前言 Linux内核提供了三种Suspend: ...

  4. Linux电源管理(6)_Generic PM之Suspend功能【重磅文章】-- wowo

    文章目录 1. 前言 2. Suspend功能有关的代码分布 1)PM Core 2)Device PM 3)Platform dependent PM 3. suspend&resume过程 ...

  5. Linux电源管理_Generic PowerManager 之Suspend功能--(一)

    1. 前言 Linux内核提供了三种Suspend: Freeze.Standby和STR(Suspend to RAM),在用户空间向"/sys/power/state"文件分别 ...

  6. Linux电源管理之 Suspend

    作者简介:Loopers,码龄11年,喜欢研究内核基本原理 suspend 代码入口 state_store函数分析 pm_suspend函数分析 enter_state函数分析 suspend_pr ...

  7. linux内核 电池管理,Linux电源管理(9)_wakelocks

    Linux电源管理(9)_wakelocks 作者:wowo 发布于:2014-9-14 23:17 分类:电源管理子系统 1. 前言 wakelocks是一个有故事的功能. wakelocks最初出 ...

  8. linux 电源管理 regulator,Linux内核电源管理综述

    资料: http://blog.csdn.net/bingqingsuimeng/article/category/1228414 http://os.chinaunix.net/a2006/0519 ...

  9. Linux电源管理(5)_Hibernate和Sleep功能介绍【转】

    本文转载自:http://www.wowotech.net/pm_subsystem/std_str_func.html 1. 前言 Hibernate和Sleep两个功能是Linux Generic ...

  10. linux系统电源时钟,linux电源管理的一些梳理

    由于项目产品需要过能源之星3.0,所以最近做了一些电源管理低功耗方面的工作,抽个时间正好梳理一下. 其实Linux 电源管理非常复杂,牵扯到很多方面,比如系统级的待机.频率电压变换.系统空闲时的处理以 ...

最新文章

  1. DIV限制宽度,字符断行,避免变形
  2. [Go] Cookie 使用简介
  3. 基于某网站的信息爬取与保存_指定跳转页
  4. cad在线转低版本_为什么别人制图那么快?41个CAD实用技巧,3天轻松玩转CAD
  5. Pandas to_numeric
  6. python文件管不了_Python文件_管道与模块编写
  7. 树莓派3B 开启串口
  8. Java字符串首字母大写
  9. uc影音java_uc影,
  10. 微信购物商城系统怎样吸引住客户,来转换为商城系统的粉丝?
  11. 360CERT网络安全11月月报 | 新增四大双重勒索病毒家族
  12. 人大金仓助力广东融合创新智慧校园建设与网络安全交流会成功举办
  13. html中图片一角的卷起效果,CSS3实现图片折角效果例子
  14. LaTeX IEEE 模板 图片引用编号为大写罗马数字问题
  15. html5 dreamlive,DREAM LIVE 5th Tour Stargazer即将开演
  16. 高等数学:第十一章 无穷级数(2)函数的幂级数展开式、傅里叶级数
  17. Visual Studio Codec#
  18. 利用Redis原子计数器incr实现计数器及接口限流
  19. 关于onKeyDown方法
  20. 我的2013年总结--北京 深圳

热门文章

  1. 解决mysql中文乱码问题。
  2. 改变iOS app的icon(iOS10.3)
  3. iOS网络开发—POST请求和GET请求
  4. 文本处理 - 测试一个对象是否是类字符串
  5. python 使用函数参数注解
  6. Mysql中,int(10)和int(11)的区别
  7. 靠播放业务吃不饱?音乐流媒体纷纷“加电商”卖周边
  8. yum使用总结(转)
  9. 斯坦福NLP笔记6 —— Defining Minimum Edit Distance
  10. svn一些基本操作含义