(linux)wake_lock机制
Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。
一、wake_lock 定义和接口
- enum {
- WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
- WAKE_LOCK_IDLE, // 阻止进入空闲模式
- WAKE_LOCK_TYPE_COUNT
- };
- 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
- };
<span style="font-size:18px;">enum { WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式 WAKE_LOCK_IDLE, // 阻止进入空闲模式 WAKE_LOCK_TYPE_COUNT }; 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 };</span>
可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。wake_lock的主要部件有锁名称、链表节点、标志位、超时时间,另外还有一个内嵌的结构用于统计锁的使用信息。接下来我们看看wake_lock对外提供的操作接口:
1、内核空间接口
- void wake_lock_init(struct wake_lock *lock, int type, const char *name);
- void wake_lock_destroy(struct wake_lock *lock);
- void wake_lock(struct wake_lock *lock);
- void wake_lock_timeout(struct wake_lock *lock, long timeout);
- void wake_unlock(struct wake_lock *lock);
<span style="font-size:18px;">void wake_lock_init(struct wake_lock *lock, int type, const char *name); void wake_lock_destroy(struct wake_lock *lock); void wake_lock(struct wake_lock *lock); void wake_lock_timeout(struct wake_lock *lock, long timeout); void wake_unlock(struct wake_lock *lock);</span>
其中wake_lock_init()用于初始化一个新锁,type参数指定了锁的类型;wake_lock_destroy()则注销一个锁;wake_lock()和wake_lock_timeout()用于将初始化完成的锁激活,使之成为有效的永久锁或者超时锁;wake_unlock()用于解锁使之成为无效锁。另外还有两个接口:
- int wake_lock_active(struct wake_lock *lock);
- long has_wake_lock(int type);
<span style="font-size:18px;">int wake_lock_active(struct wake_lock *lock); long has_wake_lock(int type);</span>
其中wake_lock_active()用于判断锁当前是否有效,如果有效则返回非0值;has_wake_lock()用于判断系统中是否还存在有效的type型锁,如果存在超时锁则返回最长的一个锁的超时时间,如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0。
2、用户空间接口
wake_lock向用户空间提供了两个文件节点用于申请锁和解锁:
- // wack_lock文件的读函数,显示用户空间定义的有效锁
- ssize_t wake_lock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_lock文件的写函数,初始化并激活用户空间定义的锁
- ssize_t wake_lock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- long timeout;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 1, &timeout);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto bad_name;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
- if (timeout)
- wake_lock_timeout(&l->wake_lock, timeout);
- else
- wake_lock(&l->wake_lock);
- bad_name:
- mutex_unlock(&tree_lock);
- return n;
- }
- // wack_unlock文件的读函数,显示用户空间的无效锁
- ssize_t wake_unlock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (!wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_unlock文件的写函数,用于用户空间解锁
- ssize_t wake_unlock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 0, NULL);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto not_found;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_unlock_store: %s\n", l->name);
- wake_unlock(&l->wake_lock);
- not_found:
- mutex_unlock(&tree_lock);
- return n;
- }
- power_attr(wake_lock);
- power_attr(wake_unlock);
<span style="font-size:18px;">// wack_lock文件的读函数,显示用户空间定义的有效锁 ssize_t wake_lock_show( struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char *s = buf; char *end = buf + PAGE_SIZE; struct rb_node *n; struct user_wake_lock *l; mutex_lock(&tree_lock); for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) { l = rb_entry(n, struct user_wake_lock, node); if (wake_lock_active(&l->wake_lock)) s += scnprintf(s, end - s, "%s ", l->name); } s += scnprintf(s, end - s, "\n"); mutex_unlock(&tree_lock); return (s - buf); } // wack_lock文件的写函数,初始化并激活用户空间定义的锁 ssize_t wake_lock_store( struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { long timeout; struct user_wake_lock *l; mutex_lock(&tree_lock); l = lookup_wake_lock_name(buf, 1, &timeout); if (IS_ERR(l)) { n = PTR_ERR(l); goto bad_name; } if (debug_mask & DEBUG_ACCESS) pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout); if (timeout) wake_lock_timeout(&l->wake_lock, timeout); else wake_lock(&l->wake_lock); bad_name: mutex_unlock(&tree_lock); return n; } // wack_unlock文件的读函数,显示用户空间的无效锁 ssize_t wake_unlock_show( struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char *s = buf; char *end = buf + PAGE_SIZE; struct rb_node *n; struct user_wake_lock *l; mutex_lock(&tree_lock); for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) { l = rb_entry(n, struct user_wake_lock, node); if (!wake_lock_active(&l->wake_lock)) s += scnprintf(s, end - s, "%s ", l->name); } s += scnprintf(s, end - s, "\n"); mutex_unlock(&tree_lock); return (s - buf); } // wack_unlock文件的写函数,用于用户空间解锁 ssize_t wake_unlock_store( struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { struct user_wake_lock *l; mutex_lock(&tree_lock); l = lookup_wake_lock_name(buf, 0, NULL); if (IS_ERR(l)) { n = PTR_ERR(l); goto not_found; } if (debug_mask & DEBUG_ACCESS) pr_info("wake_unlock_store: %s\n", l->name); wake_unlock(&l->wake_lock); not_found: mutex_unlock(&tree_lock); return n; } power_attr(wake_lock); power_attr(wake_unlock);</span>
这两个文件节点分别为"/sys/power/wake_lock"和"/sys/power/wake_unlock",应用程序可以根据HAL层的接口读写这两个节点。
二、wake_lock 实现
在linux/kernel/power/wakelock.c中我们可以看到wake_lock的实现代码,首先看看其定义的一些初始化信息:
- #define WAKE_LOCK_TYPE_MASK (0x0f) // 锁类型标志掩码
- #define WAKE_LOCK_INITIALIZED (1U << 8) // 锁已经初始化标志
- #define WAKE_LOCK_ACTIVE (1U << 9) // 锁有效标志
- #define WAKE_LOCK_AUTO_EXPIRE (1U << 10) // 超时锁标志
- #define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11) // 正在阻止休眠标志
- static DEFINE_SPINLOCK(list_lock); // 读写锁链表的自旋锁
- static LIST_HEAD(inactive_locks); // 内核维护的无效锁链表
- static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT]; // 有效锁链表
- static int current_event_num; // 休眠锁使用计数器
- struct workqueue_struct *suspend_work_queue; // 执行系统休眠的工作队列
- struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列
- struct wake_lock main_wake_lock; // 内核休眠锁
- struct wake_lock sys_sync_wake_lock; // 缓存同步锁
- suspend_state_t requested_suspend_state = PM_SUSPEND_MEM; // 系统休眠状态
- static struct wake_lock unknown_wakeup; // 未知锁
<span style="font-size:18px;">#define WAKE_LOCK_TYPE_MASK (0x0f) // 锁类型标志掩码 #define WAKE_LOCK_INITIALIZED (1U << 8) // 锁已经初始化标志 #define WAKE_LOCK_ACTIVE (1U << 9) // 锁有效标志 #define WAKE_LOCK_AUTO_EXPIRE (1U << 10) // 超时锁标志 #define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11) // 正在阻止休眠标志 static DEFINE_SPINLOCK(list_lock); // 读写锁链表的自旋锁 static LIST_HEAD(inactive_locks); // 内核维护的无效锁链表 static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT]; // 有效锁链表 static int current_event_num; // 休眠锁使用计数器 struct workqueue_struct *suspend_work_queue; // 执行系统休眠的工作队列 struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列 struct wake_lock main_wake_lock; // 内核休眠锁 struct wake_lock sys_sync_wake_lock; // 缓存同步锁 suspend_state_t requested_suspend_state = PM_SUSPEND_MEM; // 系统休眠状态 static struct wake_lock unknown_wakeup; // 未知锁</span>
在后面的分析中我们会看到这些变量的具体用途。
1、wake_lock系统初始化
- static int __init wakelocks_init(void)
- {
- int ret;
- int i;
- // 初始化有效锁链表,内核维护了2个有效锁链表
- // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式
- // WAKE_LOCK_IDLE 用于阻止进入空闲模式
- for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
- INIT_LIST_HEAD(&active_wake_locks[i]);
- #ifdef CONFIG_WAKELOCK_STAT
- // 初始化deleted_wake_locks
- wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
- "deleted_wake_locks");
- #endif
- // 初始化内核休眠锁
- wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
- // 初始化同步锁
- wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
- // 激活内核休眠锁
- wake_lock(&main_wake_lock);
- // 初始化未知锁
- wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
- // 注册power_device,power_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;
- }
- // 创建fs_sync内核进程
- sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
- if (sys_sync_work_queue == NULL) {
- pr_err ("fs_sync workqueue create failed.\n");
- }
- // 创建suspend内核进程
- suspend_work_queue = create_singlethread_workqueue("suspend");
- if (suspend_work_queue == NULL) {
- ret = -ENOMEM;
- goto err_suspend_work_queue;
- }
- #ifdef CONFIG_WAKELOCK_STAT
- // 在proc下创建wakelocks文件
- proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
- #endif
- return 0;
- 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(&unknown_wakeup);
- wake_lock_destroy(&main_wake_lock);
- #ifdef CONFIG_WAKELOCK_STAT
- wake_lock_destroy(&deleted_wake_locks);
- #endif
- return ret;
- }
- core_initcall(wakelocks_init);
<span style="font-size:18px;">static int __init wakelocks_init(void) { int ret; int i; // 初始化有效锁链表,内核维护了2个有效锁链表 // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式 // WAKE_LOCK_IDLE 用于阻止进入空闲模式 for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++) INIT_LIST_HEAD(&active_wake_locks[i]); #ifdef CONFIG_WAKELOCK_STAT // 初始化deleted_wake_locks wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND, "deleted_wake_locks"); #endif // 初始化内核休眠锁 wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main"); // 初始化同步锁 wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync"); // 激活内核休眠锁 wake_lock(&main_wake_lock); // 初始化未知锁 wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups"); // 注册power_device,power_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; } // 创建fs_sync内核进程 sys_sync_work_queue = create_singlethread_workqueue("fs_sync"); if (sys_sync_work_queue == NULL) { pr_err ("fs_sync workqueue create failed.\n"); } // 创建suspend内核进程 suspend_work_queue = create_singlethread_workqueue("suspend"); if (suspend_work_queue == NULL) { ret = -ENOMEM; goto err_suspend_work_queue; } #ifdef CONFIG_WAKELOCK_STAT // 在proc下创建wakelocks文件 proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops); #endif return 0; 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(&unknown_wakeup); wake_lock_destroy(&main_wake_lock); #ifdef CONFIG_WAKELOCK_STAT wake_lock_destroy(&deleted_wake_locks); #endif return ret; } core_initcall(wakelocks_init);</span>
可以看到内核通过core_initcall调用了wake_lock系统的初始化函数,函数首先初始化了两个有效锁的链表,用于管理系统中的有效锁;接下来初始化了deleted_wake_locks用于处理统计信息,main_wake_lock用于锁定内核(系统启动时会激活这个锁,深度休眠时需要释放这个锁),sys_sync_wake_lock用于浅度休眠阶段同步缓存时阻止内核进入深度休眠,unknown_wakeup用于唤醒时延迟0.5s进入下一次可能的深度休眠;还注册了一个platform_device用于深度休眠阶段检测是否存在有效锁;后面创建了内核进程fs_sync用于浅度休眠阶段同步缓存,内核进程suspend用于进行浅度休眠和深度休眠;还在/proc下面创建了wakelocks节点用于显示wake_lock的统计信息。
2、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
- // 初始化flag
- lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
- // 初始化链表节点
- INIT_LIST_HEAD(&lock->link);
- spin_lock_irqsave(&list_lock, irqflags);
- // 将锁加入无效锁链表
- list_add(&lock->link, &inactive_locks);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_lock_init);
<span style="font-size:18px;">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 // 初始化flag lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED; // 初始化链表节点 INIT_LIST_HEAD(&lock->link); spin_lock_irqsave(&list_lock, irqflags); // 将锁加入无效锁链表 list_add(&lock->link, &inactive_locks); spin_unlock_irqrestore(&list_lock, irqflags); } EXPORT_SYMBOL(wake_lock_init);</span>
其中参数lock为被初始化对象,type代表锁的类型,name表示锁的名称, 函数主要初始化锁的名称并设置 WAKE_LOCK_INITIALIZED 标志位,并将锁加入无效锁链表inactive_locks,当需要使用锁的时候通过wake_lock()或者wake_lock_timeout()激活该锁:
- // 根据参数激活锁
- 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);
- // 获取锁的类型
- 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
- 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
- // 设置锁有效的标志位
- if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
- lock->flags |= WAKE_LOCK_ACTIVE;
- #ifdef CONFIG_WAKELOCK_STAT
- lock->stat.last_time = ktime_get();
- #endif
- }
- // 将锁从无效锁链表中删除
- list_del(&lock->link);
- // 如果是超时锁
- 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);
- // 设置锁超时时间,以当前jiffies为基准
- 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]);
- }
- // 如果是休眠锁
- if (type == WAKE_LOCK_SUSPEND) {
- current_event_num++; // 休眠锁使用计数器加1
- #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)
- expire_in = has_wake_lock_locked(type);
- else
- expire_in = -1;
- // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in
- if (expire_in > 0) {
- 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);
- if (expire_in == 0) // 无有效锁
- queue_work(suspend_work_queue, &suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- // 激活永久锁
- void wake_lock(struct wake_lock *lock)
- {
- wake_lock_internal(lock, 0, 0);
- }
- EXPORT_SYMBOL(wake_lock);
- // 激活超时锁
- void wake_lock_timeout(struct wake_lock *lock, long timeout)
- {
- wake_lock_internal(lock, timeout, 1);
- }
- EXPORT_SYMBOL(wake_lock_timeout);
<span style="font-size:18px;">// 根据参数激活锁 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); // 获取锁的类型 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 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 // 设置锁有效的标志位 if (!(lock->flags & WAKE_LOCK_ACTIVE)) { lock->flags |= WAKE_LOCK_ACTIVE; #ifdef CONFIG_WAKELOCK_STAT lock->stat.last_time = ktime_get(); #endif } // 将锁从无效锁链表中删除 list_del(&lock->link); // 如果是超时锁 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); // 设置锁超时时间,以当前jiffies为基准 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]); } // 如果是休眠锁 if (type == WAKE_LOCK_SUSPEND) { current_event_num++; // 休眠锁使用计数器加1 #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) expire_in = has_wake_lock_locked(type); else expire_in = -1; // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in if (expire_in > 0) { 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); if (expire_in == 0) // 无有效锁 queue_work(suspend_work_queue, &suspend_work); } } spin_unlock_irqrestore(&list_lock, irqflags); } // 激活永久锁 void wake_lock(struct wake_lock *lock) { wake_lock_internal(lock, 0, 0); } EXPORT_SYMBOL(wake_lock); // 激活超时锁 void wake_lock_timeout(struct wake_lock *lock, long timeout) { wake_lock_internal(lock, timeout, 1); } EXPORT_SYMBOL(wake_lock_timeout);</span>
可以看到激活过程都是通过调用wake_lock_internal()完成的,该函数首先完成一些统计信息的初始化,设置 WAKE_LOCK_ACTIVE 标志位并将锁从无效锁链表中移除;然后根据是否是超时锁设置 WAKE_LOCK_AUTO_EXPIRE 标志位,并设置超时锁的超时时间,再将锁加入有效锁链表;最后再根据锁的类型判断是否为休眠锁,如果是休眠锁且为超时锁则通过has_wake_lock_locked()获取系统中存在的超时锁中时间最长的到期时间值,并以此值设置expire_timer,has_wake_lock_locked()返回0则表示系统中不存在有效锁则启动suspend进程开始进入深度休眠状态。
3、expire_timer
- 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);
- // 检测系统是否持有休眠锁
- 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);
- // 如果系统当前没有持有有效地休眠锁
- if (has_lock == 0)
- // 则启动深度休眠工作队列
- queue_work(suspend_work_queue, &suspend_work);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- // 定义timer,运行函数为expire_wake_locks
- static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
<span style="font-size:18px;">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); // 检测系统是否持有休眠锁 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); // 如果系统当前没有持有有效地休眠锁 if (has_lock == 0) // 则启动深度休眠工作队列 queue_work(suspend_work_queue, &suspend_work); spin_unlock_irqrestore(&list_lock, irqflags); } // 定义timer,运行函数为expire_wake_locks static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);</span>
该timer会在多个地方用到,在激活锁的函数中注册用于超时锁到期后检测系统的有效锁状态,如果系统不存在有效锁了则启动suspend进程。
4、suspend_work
- static void suspend(struct work_struct *work)
- {
- int ret;
- int entry_event_num;
- // 判断系统是否还持有有效锁,如果有则直接返回
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
- // 记录函数进入时休眠锁的使用次数
- entry_event_num = current_event_num;
- sys_sync(); // 将缓存中的数据写入磁盘
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- // 开始深度休眠
- ret = pm_suspend(requested_suspend_state);
- // 退出深度休眠,打印信息
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct timespec ts;
- struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
- }
- // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- // 激活unknown_wakeup,0.5s超时
- wake_lock_timeout(&unknown_wakeup, HZ / 2);
- }
- }
- // 声明工作队列,运行函数为suspend
- static DECLARE_WORK(suspend_work, suspend);
<span style="font-size:18px;">static void suspend(struct work_struct *work) { int ret; int entry_event_num; // 判断系统是否还持有有效锁,如果有则直接返回 if (has_wake_lock(WAKE_LOCK_SUSPEND)) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: abort suspend\n"); return; } // 记录函数进入时休眠锁的使用次数 entry_event_num = current_event_num; sys_sync(); // 将缓存中的数据写入磁盘 if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: enter suspend\n"); // 开始深度休眠 ret = pm_suspend(requested_suspend_state); // 退出深度休眠,打印信息 if (debug_mask & DEBUG_EXIT_SUSPEND) { struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("suspend: exit suspend, ret = %d " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); } // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁 if (current_event_num == entry_event_num) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: pm_suspend returned with no event\n"); // 激活unknown_wakeup,0.5s超时 wake_lock_timeout(&unknown_wakeup, HZ / 2); } } // 声明工作队列,运行函数为suspend static DECLARE_WORK(suspend_work, suspend);</span>
声明工作队列用于内核深度休眠,可以看到一个正常的休眠流程会三次调用sys_sync()用于同步缓存(之前一次在浅度休眠,之后一次在深度休眠),然后调用pm_suspend()开始执行深度休眠流程。
5、has_wake_lock
- // 移除过期超时锁
- static void expire_wake_lock(struct wake_lock *lock)
- {
- #ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 1);
- #endif
- // 清除锁有效和超时锁标志
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- // 从当前链表中删除
- list_del(&lock->link);
- // 加入无效锁链表
- list_add(&lock->link, &inactive_locks);
- if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
- pr_info("expired wake lock %s\n", lock->name);
- }
- // 打印有效锁信息,调用者需持有list_lock
- static void print_active_locks(int type)
- {
- struct wake_lock *lock;
- bool print_expired = true;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- // 遍历有效锁链表
- list_for_each_entry(lock, &active_wake_locks[type], link) {
- // 如果是超时锁
- if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
- // 计算超时剩余时间
- long timeout = lock->expires - jiffies;
- if (timeout > 0)
- pr_info("active wake lock %s, time left %ld\n",
- lock->name, timeout);
- else if (print_expired)
- pr_info("wake lock %s, expired\n", lock->name);
- } else { // 如果不是超时锁
- pr_info("active wake lock %s\n", lock->name);
- if (!debug_mask & DEBUG_EXPIRE)
- print_expired = false;
- }
- }
- }
- 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) {
- // 计算超时剩余时间
- long timeout = lock->expires - jiffies;
- // 如果锁已经过期
- if (timeout <= 0)
- // 移除过期锁
- expire_wake_lock(lock);
- else if (timeout > max_timeout) // 如果锁没有过期
- // 得到最长的一个超时时间
- max_timeout = timeout;
- } else // 如果不是超时锁则返回-1
- return -1;
- }
- return max_timeout;
- }
- // 判断系统是否还持有有效锁
- long has_wake_lock(int type)
- {
- long ret;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- // 开始判断流程
- ret = has_wake_lock_locked(type);
- // 如果还有休眠锁有效则打印状态信息
- if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
- print_active_locks(type);
- spin_unlock_irqrestore(&list_lock, irqflags);
- return ret;
- }
<span style="font-size:18px;">// 移除过期超时锁 static void expire_wake_lock(struct wake_lock *lock) { #ifdef CONFIG_WAKELOCK_STAT wake_unlock_stat_locked(lock, 1); #endif // 清除锁有效和超时锁标志 lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE); // 从当前链表中删除 list_del(&lock->link); // 加入无效锁链表 list_add(&lock->link, &inactive_locks); if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE)) pr_info("expired wake lock %s\n", lock->name); } // 打印有效锁信息,调用者需持有list_lock static void print_active_locks(int type) { struct wake_lock *lock; bool print_expired = true; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); // 遍历有效锁链表 list_for_each_entry(lock, &active_wake_locks[type], link) { // 如果是超时锁 if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) { // 计算超时剩余时间 long timeout = lock->expires - jiffies; if (timeout > 0) pr_info("active wake lock %s, time left %ld\n", lock->name, timeout); else if (print_expired) pr_info("wake lock %s, expired\n", lock->name); } else { // 如果不是超时锁 pr_info("active wake lock %s\n", lock->name); if (!debug_mask & DEBUG_EXPIRE) print_expired = false; } } } 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) { // 计算超时剩余时间 long timeout = lock->expires - jiffies; // 如果锁已经过期 if (timeout <= 0) // 移除过期锁 expire_wake_lock(lock); else if (timeout > max_timeout) // 如果锁没有过期 // 得到最长的一个超时时间 max_timeout = timeout; } else // 如果不是超时锁则返回-1 return -1; } return max_timeout; } // 判断系统是否还持有有效锁 long has_wake_lock(int type) { long ret; unsigned long irqflags; spin_lock_irqsave(&list_lock, irqflags); // 开始判断流程 ret = has_wake_lock_locked(type); // 如果还有休眠锁有效则打印状态信息 if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND) print_active_locks(type); spin_unlock_irqrestore(&list_lock, irqflags); return ret; }</span>
has_wake_lock()为系统判断当前是否存在指定类型有效锁的接口,在has_wake_lock_locked()中遍历有效锁链表,返回前面我们已经说明的值;并且打印所有有效锁的状态信息。
6、wake_unlock
- 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);
- // 将锁从有效锁链表中移除加入无效锁链表
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- // 如果是休眠锁
- if (type == WAKE_LOCK_SUSPEND) {
- // 判断系统当前是否还持有锁
- long has_lock = has_wake_lock_locked(type);
- // 如果还持有锁,设置timer到超时时间点触发
- 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 {
- if (del_timer(&expire_timer)) // 删除timer
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- 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);
- }
- EXPORT_SYMBOL(wake_unlock);
<span style="font-size:18px;">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); // 将锁从有效锁链表中移除加入无效锁链表 list_del(&lock->link); list_add(&lock->link, &inactive_locks); // 如果是休眠锁 if (type == WAKE_LOCK_SUSPEND) { // 判断系统当前是否还持有锁 long has_lock = has_wake_lock_locked(type); // 如果还持有锁,设置timer到超时时间点触发 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 { if (del_timer(&expire_timer)) // 删除timer if (debug_mask & DEBUG_EXPIRE) pr_info("wake_unlock: %s, stop expire " "timer\n", lock->name); 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); } EXPORT_SYMBOL(wake_unlock);</span>
该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否还持有有效锁,如果没有则进入深度休眠流程。
7、wake_lock_active
- // 判断锁是否有效
- int wake_lock_active(struct wake_lock *lock)
- {
- return !!(lock->flags & WAKE_LOCK_ACTIVE);
- }
- EXPORT_SYMBOL(wake_lock_active);
<span style="font-size:18px;">// 判断锁是否有效 int wake_lock_active(struct wake_lock *lock) { return !!(lock->flags & WAKE_LOCK_ACTIVE); } EXPORT_SYMBOL(wake_lock_active);</span>
8、wake_lock_destroy
- void wake_lock_destroy(struct wake_lock *lock)
- {
- unsigned long irqflags;
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock_destroy name=%s\n", lock->name);
- spin_lock_irqsave(&list_lock, irqflags);
- // 清除已经初始化的标志
- lock->flags &= ~WAKE_LOCK_INITIALIZED;
- #ifdef CONFIG_WAKELOCK_STAT
- if (lock->stat.count) {
- deleted_wake_locks.stat.count += lock->stat.count;
- deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
- deleted_wake_locks.stat.total_time =
- ktime_add(deleted_wake_locks.stat.total_time,
- lock->stat.total_time);
- deleted_wake_locks.stat.prevent_suspend_time =
- ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
- lock->stat.prevent_suspend_time);
- deleted_wake_locks.stat.max_time =
- ktime_add(deleted_wake_locks.stat.max_time,
- lock->stat.max_time);
- }
- #endif
- // 从当前链表中删除
- list_del(&lock->link);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_lock_destroy);
<span style="font-size:18px;">void wake_lock_destroy(struct wake_lock *lock) { unsigned long irqflags; if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock_destroy name=%s\n", lock->name); spin_lock_irqsave(&list_lock, irqflags); // 清除已经初始化的标志 lock->flags &= ~WAKE_LOCK_INITIALIZED; #ifdef CONFIG_WAKELOCK_STAT if (lock->stat.count) { deleted_wake_locks.stat.count += lock->stat.count; deleted_wake_locks.stat.expire_count += lock->stat.expire_count; deleted_wake_locks.stat.total_time = ktime_add(deleted_wake_locks.stat.total_time, lock->stat.total_time); deleted_wake_locks.stat.prevent_suspend_time = ktime_add(deleted_wake_locks.stat.prevent_suspend_time, lock->stat.prevent_suspend_time); deleted_wake_locks.stat.max_time = ktime_add(deleted_wake_locks.stat.max_time, lock->stat.max_time); } #endif // 从当前链表中删除 list_del(&lock->link); spin_unlock_irqrestore(&list_lock, irqflags); } EXPORT_SYMBOL(wake_lock_destroy);</span>
该函数用于注销wake_lock,首先清除 WAKE_LOCK_INITIALIZED 标志位,然后更新统计信息,最后将锁从链表中删除。
9、proc节点
- // 获取锁的剩余超时时间,通过*expire_time传递
- int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
- {
- struct timespec ts;
- struct timespec kt;
- struct timespec tomono;
- struct timespec delta;
- unsigned long seq;
- long timeout;
- // 如果不是超时锁则直接返回
- if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
- return 0;
- do {
- seq = read_seqbegin(&xtime_lock);
- // 计算超时时间点与当前时间的差值
- timeout = lock->expires - jiffies;
- // 如果时间没有到期,返回0
- if (timeout > 0)
- return 0;
- // 获取当前时间
- kt = current_kernel_time();
- tomono = wall_to_monotonic;
- } while (read_seqretry(&xtime_lock, seq));
- // 时间格式转换
- jiffies_to_timespec(-timeout, &delta);
- // 设置timespec的成员
- set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
- kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
- // 返回ts值
- *expire_time = timespec_to_ktime(ts);
- return 1;
- }
- // 打印出锁的状态信息
- static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
- {
- int lock_count = lock->stat.count;
- int expire_count = lock->stat.expire_count;
- ktime_t active_time = ktime_set(0, 0);
- ktime_t total_time = lock->stat.total_time;
- ktime_t max_time = lock->stat.max_time;
- ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
- // 如果锁有效
- if (lock->flags & WAKE_LOCK_ACTIVE) {
- ktime_t now, add_time;
- // 获取超时剩余时间
- int expired = get_expired_time(lock, &now);
- if (!expired)
- now = ktime_get();
- // 计算当前时间和上次操作时间的差值
- add_time = ktime_sub(now, lock->stat.last_time);
- lock_count++; // 使用计数加1
- if (!expired) // 如果没有到期
- active_time = add_time;
- else // 锁已经到期
- expire_count++; // 超时计数加1
- total_time = ktime_add(total_time, add_time); // 锁使用时间增加
- if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
- prevent_suspend_time = ktime_add(prevent_suspend_time,
- ktime_sub(now, last_sleep_time_update));
- if (add_time.tv64 > max_time.tv64)
- max_time = add_time;
- }
- return seq_printf(m,
- "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
- lock->name, lock_count, expire_count,
- lock->stat.wakeup_count, ktime_to_ns(active_time),
- ktime_to_ns(total_time),
- ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
- ktime_to_ns(lock->stat.last_time));
- }
- // 打印锁状态
- static int wakelock_stats_show(struct seq_file *m, void *unused)
- {
- unsigned long irqflags;
- struct wake_lock *lock;
- int ret;
- int type;
- spin_lock_irqsave(&list_lock, irqflags);
- // 输出菜单
- ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
- "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
- // 遍历无效锁链表并打印锁的状态信息
- list_for_each_entry(lock, &inactive_locks, link)
- ret = print_lock_stat(m, lock);
- // 遍历有效锁链表并打印锁的状态信息
- for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
- list_for_each_entry(lock, &active_wake_locks[type], link)
- ret = print_lock_stat(m, lock);
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- return 0;
- }
- // proc文件打开函数,调用show函数显示当前所有的锁信息
- static int wakelock_stats_open(struct inode *inode, struct file *file)
- {
- return single_open(file, wakelock_stats_show, NULL);
- }
- // proc文件系统操作函数
- static const struct file_operations wakelock_stats_fops = {
- .owner = THIS_MODULE,
- .open = wakelock_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
<span style="font-size:18px;">// 获取锁的剩余超时时间,通过*expire_time传递 int get_expired_time(struct wake_lock *lock, ktime_t *expire_time) { struct timespec ts; struct timespec kt; struct timespec tomono; struct timespec delta; unsigned long seq; long timeout; // 如果不是超时锁则直接返回 if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE)) return 0; do { seq = read_seqbegin(&xtime_lock); // 计算超时时间点与当前时间的差值 timeout = lock->expires - jiffies; // 如果时间没有到期,返回0 if (timeout > 0) return 0; // 获取当前时间 kt = current_kernel_time(); tomono = wall_to_monotonic; } while (read_seqretry(&xtime_lock, seq)); // 时间格式转换 jiffies_to_timespec(-timeout, &delta); // 设置timespec的成员 set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec, kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec); // 返回ts值 *expire_time = timespec_to_ktime(ts); return 1; } // 打印出锁的状态信息 static int print_lock_stat(struct seq_file *m, struct wake_lock *lock) { int lock_count = lock->stat.count; int expire_count = lock->stat.expire_count; ktime_t active_time = ktime_set(0, 0); ktime_t total_time = lock->stat.total_time; ktime_t max_time = lock->stat.max_time; ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time; // 如果锁有效 if (lock->flags & WAKE_LOCK_ACTIVE) { ktime_t now, add_time; // 获取超时剩余时间 int expired = get_expired_time(lock, &now); if (!expired) now = ktime_get(); // 计算当前时间和上次操作时间的差值 add_time = ktime_sub(now, lock->stat.last_time); lock_count++; // 使用计数加1 if (!expired) // 如果没有到期 active_time = add_time; else // 锁已经到期 expire_count++; // 超时计数加1 total_time = ktime_add(total_time, add_time); // 锁使用时间增加 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) prevent_suspend_time = ktime_add(prevent_suspend_time, ktime_sub(now, last_sleep_time_update)); if (add_time.tv64 > max_time.tv64) max_time = add_time; } return seq_printf(m, "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n", lock->name, lock_count, expire_count, lock->stat.wakeup_count, ktime_to_ns(active_time), ktime_to_ns(total_time), ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time), ktime_to_ns(lock->stat.last_time)); } // 打印锁状态 static int wakelock_stats_show(struct seq_file *m, void *unused) { unsigned long irqflags; struct wake_lock *lock; int ret; int type; spin_lock_irqsave(&list_lock, irqflags); // 输出菜单 ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since" "\ttotal_time\tsleep_time\tmax_time\tlast_change\n"); // 遍历无效锁链表并打印锁的状态信息 list_for_each_entry(lock, &inactive_locks, link) ret = print_lock_stat(m, lock); // 遍历有效锁链表并打印锁的状态信息 for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) { list_for_each_entry(lock, &active_wake_locks[type], link) ret = print_lock_stat(m, lock); } spin_unlock_irqrestore(&list_lock, irqflags); return 0; } // proc文件打开函数,调用show函数显示当前所有的锁信息 static int wakelock_stats_open(struct inode *inode, struct file *file) { return single_open(file, wakelock_stats_show, NULL); } // proc文件系统操作函数 static const struct file_operations wakelock_stats_fops = { .owner = THIS_MODULE, .open = wakelock_stats_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, };</span>
以上是proc节点的操作接口,在wakelocks_init中注册。
总结:通过以上分析我们可以看到启动深度休眠流程有四个可能的地方,分别为expire_timer、wake_lock、wake_lock_timeout、wake_unlock,其中expire_timer和wake_unlock最常见。