Linux电源管理-wakelock
前言
/** kernel/power/wakelock.c** User space wakeup sources support.** Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>** This code is based on the analogous interface allowing user space to* manipulate wakelocks on Android.*/
wakelock对比
user space | kernel | |
旧wakelock |
往/sys/power/wake_lock写入字符串阻止系统进入suspend。 往/sys/power/wake_unlock写入字符串系统可以进入suspend。 |
wakelock在suspend的流程上加把锁,阻止suspend。 wakeunlock就是去掉这把锁。 |
新wakelock |
基于wakeup event framework机制。 wakelock就是在kernel space激活一个wakeup event。 wakeunlock就是deactive一个wakeup event。 |
对user space来说,wakelock还是以前的wakelock,使用方法没变,API也没有变化。
数据结构
struct wakelock {char *name;struct rb_node node;struct wakeup_source ws;
#ifdef CONFIG_PM_WAKELOCKS_GCstruct list_head lru;
#endif
};
.name: 该wakelock对应的name。
代码分析
static ssize_t wake_lock_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{int error = pm_wake_lock(buf);return error ? error : n;
}
此函数直接调用了pm_wake_lock函数。
int pm_wake_lock(const char *buf)
{const char *str = buf;struct wakelock *wl;u64 timeout_ns = 0;size_t len;int ret = 0;if (!capable(CAP_BLOCK_SUSPEND))return -EPERM;while (*str && !isspace(*str))str++;len = str - buf;if (!len)return -EINVAL;if (*str && *str != '\n') {/* Find out if there's a valid timeout string appended. */ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);if (ret)return -EINVAL;}mutex_lock(&wakelocks_lock);wl = wakelock_lookup_add(buf, len, true);if (IS_ERR(wl)) {ret = PTR_ERR(wl);goto out;}if (timeout_ns) {u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;do_div(timeout_ms, NSEC_PER_MSEC);__pm_wakeup_event(&wl->ws, timeout_ms);} else {__pm_stay_awake(&wl->ws);}wakelocks_lru_most_recent(wl);out:mutex_unlock(&wakelocks_lock);return ret;
}
1. 判断当前task是否有suspend系统的权限。
static struct wakelock *wakelock_lookup_add(const char *name, size_t len,bool add_if_not_found)
{struct rb_node **node = &wakelocks_tree.rb_node;struct rb_node *parent = *node;struct wakelock *wl;while (*node) {int diff;parent = *node;wl = rb_entry(*node, struct wakelock, node);diff = strncmp(name, wl->name, len);if (diff == 0) {if (wl->name[len])diff = -1;elsereturn wl;}if (diff < 0)node = &(*node)->rb_left;elsenode = &(*node)->rb_right;}if (!add_if_not_found)return ERR_PTR(-EINVAL);if (wakelocks_limit_exceeded())return ERR_PTR(-ENOSPC);/* Not found, we have to add a new one. */wl = kzalloc(sizeof(*wl), GFP_KERNEL);if (!wl)return ERR_PTR(-ENOMEM);wl->name = kstrndup(name, len, GFP_KERNEL);if (!wl->name) {kfree(wl);return ERR_PTR(-ENOMEM);}wl->ws.name = wl->name;wakeup_source_add(&wl->ws);rb_link_node(&wl->node, parent, node);rb_insert_color(&wl->node, &wakelocks_tree);wakelocks_lru_add(wl);increment_wakelocks_number();return wl;
}
1. 获取红黑树的root节点,通过while循环,在红黑树中根据wakelock的name查找是否有相同的,如果查找到,返回该wakelock。
static inline bool wakelocks_limit_exceeded(void)
{return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
}
通常CONFIG_PM_WAKELOCKS_LIMIT的数目为100。
static inline void wakelocks_lru_add(struct wakelock *wl)
{list_add(&wl->lru, &wakelocks_lru_list);
}
static ssize_t wake_unlock_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{int error = pm_wake_unlock(buf);return error ? error : n;
}
此函数最终调用pm_wake_unlock接口。
int pm_wake_unlock(const char *buf)
{struct wakelock *wl;size_t len;int ret = 0;if (!capable(CAP_BLOCK_SUSPEND))return -EPERM;len = strlen(buf);if (!len)return -EINVAL;if (buf[len-1] == '\n')len--;if (!len)return -EINVAL;mutex_lock(&wakelocks_lock);wl = wakelock_lookup_add(buf, len, false);if (IS_ERR(wl)) {ret = PTR_ERR(wl);goto out;}__pm_relax(&wl->ws);wakelocks_lru_most_recent(wl);wakelocks_gc();out:mutex_unlock(&wakelocks_lock);return ret;
}
1. 依旧需要判断当前task是否有suspend系统的权限。
ssize_t pm_show_wakelocks(char *buf, bool show_active)
{struct rb_node *node;struct wakelock *wl;char *str = buf;char *end = buf + PAGE_SIZE;mutex_lock(&wakelocks_lock);for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {wl = rb_entry(node, struct wakelock, node);if (wl->ws.active == show_active)str += scnprintf(str, end - str, "%s ", wl->name);}if (str > buf)str--;str += scnprintf(str, end - str, "\n");mutex_unlock(&wakelocks_lock);return (str - buf);
}
此函数也就是遍历红黑树,通过show_active变量判断当前是lock或者unlock的。最后show出来即可。
wakelock垃圾回收
static LIST_HEAD(wakelocks_lru_list);
2. 定义一个变量,记录系统中wakelock的数量。
static unsigned int wakelocks_gc_count;
3. 当创建wakelock的时候调用wakelocks_lru_add函数,将此wakelock添加到wakelock_lru链表head部。
static inline void wakelocks_lru_add(struct wakelock *wl)
{list_add(&wl->lru, &wakelocks_lru_list);
}
4. 当调用unlock的时候,调用wakelocks_lru_most_recent函数,将wakelock移动到链表的head部,表示此wakelock是最近访问的。
static void wakelocks_gc(void)
{struct wakelock *wl, *aux;ktime_t now;if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)return;now = ktime_get();list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {u64 idle_time_ns;bool active;spin_lock_irq(&wl->ws.lock);idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));active = wl->ws.active;spin_unlock_irq(&wl->ws.lock);if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))break;if (!active) {wakeup_source_remove(&wl->ws);rb_erase(&wl->node, &wakelocks_tree);list_del(&wl->lru);kfree(wl->name);kfree(wl);decrement_wakelocks_number();}}wakelocks_gc_count = 0;
}
a. 如果当前系统wakelock小于系统上限(WL_GC_COUNT_MAX=100),则不用回收。
Linux电源管理-wakelock相关推荐
- Linux电源管理(1)_整体架构 -- wowo
1. 前言 在这个世界中,任何系统的运转都需要能量.如树木依靠光能生长,如马儿依靠食物奔跑,如计算机系统依靠电能运行.而能量的获取是有成本的,因此如果能在保证系统运转的基础上,尽量节省对能量的消耗,就 ...
- linux内核 电池管理,Linux电源管理(9)_wakelocks
Linux电源管理(9)_wakelocks 作者:wowo 发布于:2014-9-14 23:17 分类:电源管理子系统 1. 前言 wakelocks是一个有故事的功能. wakelocks最初出 ...
- Linux电源管理(10)_autosleep
Linux电源管理(10)_autosleep 作者:wowo 发布于:2014-9-18 23:42 分类:电源管理子系统 1. 前言 Autosleep也是从Android wakelocks补丁 ...
- linux 电源管理 regulator,Linux内核电源管理综述
资料: http://blog.csdn.net/bingqingsuimeng/article/category/1228414 http://os.chinaunix.net/a2006/0519 ...
- Linux电源管理(5)_Hibernate和Sleep功能介绍【转】
本文转载自:http://www.wowotech.net/pm_subsystem/std_str_func.html 1. 前言 Hibernate和Sleep两个功能是Linux Generic ...
- linux 电池管理软件,Linux电源管理(2)_Generic PM之基本概念和软件架构
Linux电源管理(2)_Generic PM之基本概念和软件架构 作者:wowo 发布于:2014-5-13 19:24 分类:电源管理子系统 1. 前言 这里的Generic PM,是蜗蜗自己起的 ...
- linux系统电源时钟,linux电源管理的一些梳理
由于项目产品需要过能源之星3.0,所以最近做了一些电源管理低功耗方面的工作,抽个时间正好梳理一下. 其实Linux 电源管理非常复杂,牵扯到很多方面,比如系统级的待机.频率电压变换.系统空闲时的处理以 ...
- Linux电源管理(2)_Generic PM之基本概念和软件架构(蜗窝科技,www.wowotech.net)
1. 前言 这里的Generic PM,是蜗蜗自己起的名字,指Linux系统中那些常规的电源管理手段,包括关机(Power off).待机(Standby or Hibernate).重启(Reboo ...
- 九万字图文讲透彻 Linux 电源管理及实例分析
九万字图文讲透彻 Linux 电源管理及实例分析. 计算机运行在物理世界中,物理世界中的一切活动都需要消耗能量.能量的形式有很多种,如热能.核能.化学能等.计算机消耗的是电能,其来源是电池或者外电源. ...
- linux 电源管理 Generic PM之Suspend功能
Linux电源管理(6)_Generic PM之Suspend功能 作者:wowo 发布于:2014-8-22 21:40 分类:电源管理子系统 1. 前言 Linux内核提供了三种Suspend: ...
最新文章
- Recyclerview 出现 java.lang.IndexOutOfBoundsException: Inconsistency detected 异常
- 【ruoyi若依】layer 重置大小/resize
- “云原生”为什么对云计算生态充满吸引力?
- document.getElementById() id是变量
- python设置cookie_Python中cookie的设置方法
- matlab 移动平均_两所高校被禁用MATLAB背后,是工业设计能力之争
- 基于web的工作流设计器(多比图形控件)
- linux 调优系列(续)
- java多级目录文件是否存在_Java文件夹操作,判断多级路径是否存在,不存在就创建(包括windows和linux下的路径字符分析)...
- Java跳出多重循环的方法
- [xsy2282]cake
- mac新手入门:从启动台Launchpad中完全删除应用程序
- 使用 SASS 混合器 和@media 适应分辨率变化
- maven mybatis实现递归查询和使用存储过程
- 什么事件必须要我王二狗来处理?
- 静电纺聚丙烯腈纳米级纤维滤膜的制备
- PaddlePaddle第二周学习笔记
- leetcode-841-钥匙和房间 题解
- 网络规划设计师5天修炼-施游-专题视频课程
- python中fact()是什么意思_python中fact函数是什么及如何使用?
热门文章
- java之接口适配器
- cocos2d-x关于CCTableView的“乱序问题”的理解
- Delphi中ListView和TreeView的Item中的内存泄露
- 《狂人C》阅读笔记(1)
- 湖北师范学院c语言试题题库,2017年湖北师范学院计算机科学与技术学院803数据结构与C语言程序设计考研题库...
- 阿里云解决方案架构师,讲述分布式架构云平台解决方案(附图文)
- js my_first
- python 异常学习2
- celery+rabbitmq+redis 分布任务队列探索(一)
- Andro - Multipurpose OpenCart 2.X 自适应主题模板 ABC-0651