-
//based on linux v3.14 source code
-
一、概述
-
Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得. 这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁. 如果没有锁了或者超时了, 内核就会启动休眠的那套机制来进入休眠.
-
-
二、相关结构体
-
struct wake_lock {
-
#ifdef CONFIG_HAS_WAKELOCK
-
struct list_head link; //链入锁链表节点
-
int flags; //锁标志
-
const char *name; //锁名字
-
unsigned long expires; //超时时间
-
#ifdef CONFIG_WAKELOCK_STAT
-
struct {
-
int count;
-
int expire_count;
-
int wakeup_count;
-
ktime_t total_time;
-
ktime_t prevent_suspend_time;
-
ktime_t max_time;
-
ktime_t last_time;
-
} stat; //记录锁信息
-
#endif
-
#endif
-
};
-
-
三、wakelocks初始化
-
1. 内核维护了两个活动锁链表,active_wake_locks[WAKE_LOCK_TYPE_COUNT]。
-
1.1 active_wake_locks[0]维护的是suspend lock.WAKE_LOCK_SUSPEND这种锁如果被某个task持有,那么系统将无法进入休眠。
-
1.2 active_wake_locks[1]维护的是idle lock.WAKE_LOCK_IDLE这种锁不会影响到系统进入休眠,但是如果这种锁被持有,那么系统将无法进入idle空闲模式。
-
2. 内核维护了还一个非活动锁链表inactive_locks,用来记录所有处于inactive状态的锁.
-
-
static int __init wakelocks_init(void)
-
{
-
int ret;
-
int i;
-
-
//初始化active_wake_locks数组中的两个类型锁链表: WAKE_LOCK_SUSPEND,WAKE_LOCK_IDLE
-
for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
-
INIT_LIST_HEAD(&active_wake_locks[i]);
-
-
//初始化wakelock deleted_wake_locks,同时将其加入到非活动锁链表中
-
#ifdef CONFIG_WAKELOCK_STAT
-
wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,"deleted_wake_locks");
-
#endif
-
-
// 初始化wakelock: main, sys_sync, unknown_wakeups, 同时将其加入到非活动锁链表中
-
//给main_wake_lock 加锁
-
wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
-
wake_lock(&main_wake_lock);
-
wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
-
wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,"suspend_backoff");
-
-
//platform device 和 driver注册
-
ret = platform_device_register(&power_device);
-
if (ret) {
-
pr_err("wakelocks_init: platform_device_register failed\n");
-
goto err_platform_device_register;
-
}
-
ret = platform_driver_register(&power_driver);
-
if (ret) {
-
pr_err("wakelocks_init: platform_driver_register failed\n");
-
goto err_platform_driver_register;
-
}
-
-
//新建工作队列和工作者内核线程
-
INIT_COMPLETION(suspend_sys_sync_comp);
-
suspend_sys_sync_work_queue = create_singlethread_workqueue("suspend_sys_sync");
-
if (suspend_sys_sync_work_queue == NULL) {
-
ret = -ENOMEM;
-
goto err_suspend_sys_sync_work_queue;
-
}
-
-
suspend_work_queue = create_singlethread_workqueue("suspend");
-
if (suspend_work_queue == NULL) {
-
ret = -ENOMEM;
-
goto err_suspend_work_queue;
-
}
-
-
//创建proc接口
-
#ifdef CONFIG_WAKELOCK_STAT
-
proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
-
#endif
-
-
return 0;
-
-
err_suspend_sys_sync_work_queue:
-
err_suspend_work_queue:
-
platform_driver_unregister(&power_driver);
-
err_platform_driver_register:
-
platform_device_unregister(&power_device);
-
err_platform_device_register:
-
wake_lock_destroy(&suspend_backoff_lock);
-
wake_lock_destroy(&unknown_wakeup);
-
wake_lock_destroy(&main_wake_lock);
-
#ifdef CONFIG_WAKELOCK_STAT
-
wake_lock_destroy(&deleted_wake_locks);
-
#endif
-
return ret;
-
}
-
-
四、wake lock使用
-
1. 初始化一个wake lock锁
-
//该函数设置锁的名字,类型,最后将新建的锁挂接到一个专门链接这些非锁状态的链表inactive_locks上(新建的wakelock初期都是处于非锁状态的,除非显示调用函数wake_lock来上锁)。
-
void wake_lock_init(struct wake_lock *lock, int type, const char *name)
-
{
-
unsigned long irqflags = 0;
-
-
if (name)
-
lock->name = name;
-
BUG_ON(!lock->name);
-
-
if (debug_mask & DEBUG_WAKE_LOCK)
-
pr_info("wake_lock_init name=%s\n", lock->name);
-
#ifdef CONFIG_WAKELOCK_STAT
-
lock->stat.count = 0;
-
lock->stat.expire_count = 0;
-
lock->stat.wakeup_count = 0;
-
lock->stat.total_time = ktime_set(0, 0);
-
lock->stat.prevent_suspend_time = ktime_set(0, 0);
-
lock->stat.max_time = ktime_set(0, 0);
-
lock->stat.last_time = ktime_set(0, 0);
-
#endif
-
lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
-
-
INIT_LIST_HEAD(&lock->link);
-
spin_lock_irqsave(&list_lock, irqflags);
-
//将锁挂到非锁状态的链表inactive_locks上
-
list_add(&lock->link, &inactive_locks);
-
spin_unlock_irqrestore(&list_lock, irqflags);
-
}
-
-
2. 上锁
-
wakelock有两种形式的锁:超时锁和非超时锁,这两种形式的锁都是使用函数wake_lock_init()来初始化,只是在上锁的时候会有一点点差别,超时锁使用函数wake_lock_timeout(),而非超时锁使用函数wake_lock(), 这个两个函数会最终调用到同一个函数wake_lock_internal(),该函数依靠传入的不同参数来选择不同的路径来工作。值得注意的是,非超时锁必须手工解锁,否则系统永远不能进入睡眠。
-
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
-
void wake_lock(struct wake_lock *lock)
-
{
-
wake_lock_internal(lock, 0, 0);
-
}
-
-
void wake_lock_timeout(struct wake_lock *lock, long timeout)
-
{
-
wake_lock_internal(lock, timeout, 1);
-
}
-
-
static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)
-
{
-
int type;
-
unsigned long irqflags;
-
long expire_in;
-
-
spin_lock_irqsave(&list_lock, irqflags);
-
//上锁前,检查锁类型和有效性,是否为WAKE_LOCK_SUSPEND或WAKE_LOCK_IDLE某一种
-
type = lock->flags & WAKE_LOCK_TYPE_MASK;
-
BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
-
BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
-
#ifdef CONFIG_WAKELOCK_STAT
-
//检查wait_for_wakeup标志
-
if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
-
if (debug_mask & DEBUG_WAKEUP)
-
pr_info("wakeup wake lock: %s\n", lock->name);
-
wait_for_wakeup = 0;
-
lock->stat.wakeup_count++;
-
}
-
//检查超时锁
-
if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
-
(long)(lock->expires - jiffies) <= 0) {
-
wake_unlock_stat_locked(lock, 0);//若超时,则解锁
-
lock->stat.last_time = ktime_get();
-
}
-
#endif
-
//上锁,设置WAKE_LOCK_ACTIVE标志
-
if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
-
lock->flags |= WAKE_LOCK_ACTIVE;
-
#ifdef CONFIG_WAKELOCK_STAT
-
lock->stat.last_time = ktime_get();
-
#endif
-
}
-
//lock从非锁状态的链表inactive_locks上删除
-
list_del(&lock->link);
-
-
//has_timeout=1,表示是超时锁
-
if (has_timeout) {
-
if (debug_mask & DEBUG_WAKE_LOCK)
-
pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
-
lock->name, type, timeout / HZ,
-
(timeout % HZ) * MSEC_PER_SEC / HZ);
-
//设置超时时间
-
lock->expires = jiffies + timeout;
-
lock->flags |= WAKE_LOCK_AUTO_EXPIRE;//超时锁标志
-
//超时锁重新挂入链表尾
-
list_add_tail(&lock->link, &active_wake_locks[type]);
-
} else {
-
//非超时锁
-
if (debug_mask & DEBUG_WAKE_LOCK)
-
pr_info("wake_lock: %s, type %d\n", lock->name, type);
-
lock->expires = LONG_MAX;
-
lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;//非超时锁标志
-
//非超时锁直接挂入链表
-
list_add(&lock->link, &active_wake_locks[type]);
-
}
-
-
//对于WAKE_LOCK_SUSPEND型的锁
-
if (type == WAKE_LOCK_SUSPEND) {
-
current_event_num++;
-
#ifdef CONFIG_WAKELOCK_STAT
-
if (lock == &main_wake_lock)
-
update_sleep_wait_stats_locked(1);
-
else if (!wake_lock_active(&main_wake_lock))
-
update_sleep_wait_stats_locked(0);
-
#endif
-
if (has_timeout)
-
//检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁(即在 active_wake_locks 链表上的WAKE_LOCK_SUSPEND 锁,或者说当前被加锁了的 WAKE_LOCK_SUSPEND 锁),是否有超期锁已经过期,如果有则把过期超期锁从 active_wake_locks 上删除,挂到 inactive_locks 上。同时它还检查链表上有没有非超期锁,如果有则直接返回-1,否则它最终返回的是所有超期锁过期时间的最大值
-
expire_in = has_wake_lock_locked(type);
-
else
-
expire_in = -1;
-
-
//如果 has_wake_lock_locked 函数返回的是-1(表示当前活动锁有非超时锁)或者 0(表示所有活动锁都是超时锁,且全已经超时),则删除 expire_timer,并排队一个 suspend 工作到 suspend_work_queue 工作队列,最终系统会suspend
-
if (expire_in > 0) {
-
//有超时锁,设置超时定时器,超时调用expire_wake_locks函数
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("wake_lock: %s, start expire timer, ""%ld\n", lock->name, expire_in);
-
mod_timer(&expire_timer, jiffies + expire_in);
-
} else {
-
//无超时锁,删除超时定时器
-
if (del_timer(&expire_timer))
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("wake_lock: %s, stop expire timer\n",lock->name);
-
//如果超时锁为0,且无非超时锁时,expire_in为0,启动suspend_work_queue工作队列进行suspend
-
//也就是说链表active_wake_locks[WAKE_LOCK_SUSPEND]为NULL,就没有锁阻止系统进入suspend了,那么系统就可以执行suspend的流程了。
-
if (expire_in == 0)
-
queue_work(suspend_work_queue, &suspend_work);
-
}
-
}
-
spin_unlock_irqrestore(&list_lock, irqflags);
-
}
-
-
3. 解锁
-
void wake_unlock(struct wake_lock *lock)
-
{
-
int type;
-
unsigned long irqflags;
-
spin_lock_irqsave(&list_lock, irqflags);
-
type = lock->flags & WAKE_LOCK_TYPE_MASK;
-
#ifdef CONFIG_WAKELOCK_STAT
-
wake_unlock_stat_locked(lock, 0);
-
#endif
-
if (debug_mask & DEBUG_WAKE_LOCK)
-
pr_info("wake_unlock: %s\n", lock->name);
-
//去锁标志
-
lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
-
//该锁从active_wake_locks[type]链表移除,加入inactive_locks链表
-
list_del(&lock->link);
-
list_add(&lock->link, &inactive_locks);
-
-
//前面已经说了只有类型为WAKE_LOCK_SUSPEND的wakelock被上锁才会阻止系统进入suspend,那么也就是说只要链表active_wake_locks[WAKE_LOCK_SUSPEND]为NULL,就没有锁阻止系统进入suspend了,那么系统就可以执行suspend的流程了。
-
if (type == WAKE_LOCK_SUSPEND) {
-
//检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁
-
long has_lock = has_wake_lock_locked(type);
-
//has_lock>0表示有超时锁,has_lock为最大超时时间,设置定时器,超时调用expire_wake_locks函数
-
if (has_lock > 0) {
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("wake_unlock: %s, start expire timer, ""%ld\n", lock->name, has_lock);
-
mod_timer(&expire_timer, jiffies + has_lock);
-
} else {
-
//has_lock=-1,表示有非超时锁。
-
if (del_timer(&expire_timer))
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("wake_unlock: %s, stop expire ""timer\n", lock->name);
-
//如果has_lock=0,表示超时锁已超时时间为0,且无非超时锁时,启动suspend流程
-
if (has_lock == 0)
-
queue_work(suspend_work_queue, &suspend_work);
-
}
-
if (lock == &main_wake_lock) {
-
if (debug_mask & DEBUG_SUSPEND)
-
print_active_locks(WAKE_LOCK_SUSPEND);
-
#ifdef CONFIG_WAKELOCK_STAT
-
update_sleep_wait_stats_locked(0);
-
#endif
-
}
-
}
-
spin_unlock_irqrestore(&list_lock, irqflags);
-
}
-
-
4. 设置超时锁时,设置超时定时器,超时时会回调定时器函数
-
static void expire_wake_locks(unsigned long data)
-
{
-
long has_lock;
-
unsigned long irqflags;
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("expire_wake_locks: start\n");
-
spin_lock_irqsave(&list_lock, irqflags);
-
if (debug_mask & DEBUG_SUSPEND)
-
print_active_locks(WAKE_LOCK_SUSPEND);
-
-
//检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁
-
has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
-
if (debug_mask & DEBUG_EXPIRE)
-
pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
-
-
//如果没有SUSPEND类型的wakelock处于active,那么将调用suspend
-
if (has_lock == 0)
-
queue_work(suspend_work_queue, &suspend_work);
-
spin_unlock_irqrestore(&list_lock, irqflags);
-
}
-
-
static long has_wake_lock_locked(int type)
-
{
-
struct wake_lock *lock, *n;
-
long max_timeout = 0;
-
-
BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
-
//遍历链表中的所有锁
-
list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
-
//若设置了超时锁标志
-
if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
-
//计算还剩余的时间