Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。

一、wake_lock 定义和接口

  1. enum {
  2. WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
  3. WAKE_LOCK_IDLE,    // 阻止进入空闲模式
  4. WAKE_LOCK_TYPE_COUNT
  5. };
  6. struct wake_lock {
  7. #ifdef CONFIG_HAS_WAKELOCK
  8. struct list_head    link;     // 链表节点
  9. int                 flags;    // 标志
  10. const char         *name;     // 名称
  11. unsigned long       expires;  // 超时时间
  12. #ifdef CONFIG_WAKELOCK_STAT
  13. struct {
  14. int             count;         // 使用计数
  15. int             expire_count;  // 超时计数
  16. int             wakeup_count;  // 唤醒计数
  17. ktime_t         total_time;    // 锁使用时间
  18. ktime_t         prevent_suspend_time;  // 锁阻止休眠的时间
  19. ktime_t         max_time;      // 锁使用时间最长的一次
  20. ktime_t         last_time;     // 锁上次操作时间
  21. } stat;
  22. #endif
  23. #endif
  24. };
<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、内核空间接口

  1. void wake_lock_init(struct wake_lock *lock, int type, const char *name);
  2. void wake_lock_destroy(struct wake_lock *lock);
  3. void wake_lock(struct wake_lock *lock);
  4. void wake_lock_timeout(struct wake_lock *lock, long timeout);
  5. 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()用于解锁使之成为无效锁。另外还有两个接口:

  1. int wake_lock_active(struct wake_lock *lock);
  2. 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向用户空间提供了两个文件节点用于申请锁和解锁:

  1. // wack_lock文件的读函数,显示用户空间定义的有效锁
  2. ssize_t wake_lock_show(
  3. struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  4. {
  5. char *s = buf;
  6. char *end = buf + PAGE_SIZE;
  7. struct rb_node *n;
  8. struct user_wake_lock *l;
  9. mutex_lock(&tree_lock);
  10. for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
  11. l = rb_entry(n, struct user_wake_lock, node);
  12. if (wake_lock_active(&l->wake_lock))
  13. s += scnprintf(s, end - s, "%s ", l->name);
  14. }
  15. s += scnprintf(s, end - s, "\n");
  16. mutex_unlock(&tree_lock);
  17. return (s - buf);
  18. }
  19. // wack_lock文件的写函数,初始化并激活用户空间定义的锁
  20. ssize_t wake_lock_store(
  21. struct kobject *kobj, struct kobj_attribute *attr,
  22. const char *buf, size_t n)
  23. {
  24. long timeout;
  25. struct user_wake_lock *l;
  26. mutex_lock(&tree_lock);
  27. l = lookup_wake_lock_name(buf, 1, &timeout);
  28. if (IS_ERR(l)) {
  29. n = PTR_ERR(l);
  30. goto bad_name;
  31. }
  32. if (debug_mask & DEBUG_ACCESS)
  33. pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
  34. if (timeout)
  35. wake_lock_timeout(&l->wake_lock, timeout);
  36. else
  37. wake_lock(&l->wake_lock);
  38. bad_name:
  39. mutex_unlock(&tree_lock);
  40. return n;
  41. }
  42. // wack_unlock文件的读函数,显示用户空间的无效锁
  43. ssize_t wake_unlock_show(
  44. struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  45. {
  46. char *s = buf;
  47. char *end = buf + PAGE_SIZE;
  48. struct rb_node *n;
  49. struct user_wake_lock *l;
  50. mutex_lock(&tree_lock);
  51. for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
  52. l = rb_entry(n, struct user_wake_lock, node);
  53. if (!wake_lock_active(&l->wake_lock))
  54. s += scnprintf(s, end - s, "%s ", l->name);
  55. }
  56. s += scnprintf(s, end - s, "\n");
  57. mutex_unlock(&tree_lock);
  58. return (s - buf);
  59. }
  60. // wack_unlock文件的写函数,用于用户空间解锁
  61. ssize_t wake_unlock_store(
  62. struct kobject *kobj, struct kobj_attribute *attr,
  63. const char *buf, size_t n)
  64. {
  65. struct user_wake_lock *l;
  66. mutex_lock(&tree_lock);
  67. l = lookup_wake_lock_name(buf, 0, NULL);
  68. if (IS_ERR(l)) {
  69. n = PTR_ERR(l);
  70. goto not_found;
  71. }
  72. if (debug_mask & DEBUG_ACCESS)
  73. pr_info("wake_unlock_store: %s\n", l->name);
  74. wake_unlock(&l->wake_lock);
  75. not_found:
  76. mutex_unlock(&tree_lock);
  77. return n;
  78. }
  79. power_attr(wake_lock);
  80. 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的实现代码,首先看看其定义的一些初始化信息:

  1. #define WAKE_LOCK_TYPE_MASK              (0x0f)     // 锁类型标志掩码
  2. #define WAKE_LOCK_INITIALIZED            (1U << 8)  // 锁已经初始化标志
  3. #define WAKE_LOCK_ACTIVE                 (1U << 9)  // 锁有效标志
  4. #define WAKE_LOCK_AUTO_EXPIRE            (1U << 10) // 超时锁标志
  5. #define WAKE_LOCK_PREVENTING_SUSPEND     (1U << 11) // 正在阻止休眠标志
  6. static DEFINE_SPINLOCK(list_lock);  // 读写锁链表的自旋锁
  7. static LIST_HEAD(inactive_locks);   // 内核维护的无效锁链表
  8. static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];  // 有效锁链表
  9. static int current_event_num;       // 休眠锁使用计数器
  10. struct workqueue_struct *suspend_work_queue;  // 执行系统休眠的工作队列
  11. struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列
  12. struct wake_lock main_wake_lock;              // 内核休眠锁
  13. struct wake_lock sys_sync_wake_lock;          // 缓存同步锁
  14. suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;  // 系统休眠状态
  15. 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系统初始化

  1. static int __init wakelocks_init(void)
  2. {
  3. int ret;
  4. int i;
  5. // 初始化有效锁链表,内核维护了2个有效锁链表
  6. // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式
  7. // WAKE_LOCK_IDLE    用于阻止进入空闲模式
  8. for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
  9. INIT_LIST_HEAD(&active_wake_locks[i]);
  10. #ifdef CONFIG_WAKELOCK_STAT
  11. // 初始化deleted_wake_locks
  12. wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
  13. "deleted_wake_locks");
  14. #endif
  15. // 初始化内核休眠锁
  16. wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
  17. // 初始化同步锁
  18. wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
  19. // 激活内核休眠锁
  20. wake_lock(&main_wake_lock);
  21. // 初始化未知锁
  22. wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
  23. // 注册power_device,power_driver
  24. ret = platform_device_register(&power_device);
  25. if (ret) {
  26. pr_err("wakelocks_init: platform_device_register failed\n");
  27. goto err_platform_device_register;
  28. }
  29. ret = platform_driver_register(&power_driver);
  30. if (ret) {
  31. pr_err("wakelocks_init: platform_driver_register failed\n");
  32. goto err_platform_driver_register;
  33. }
  34. // 创建fs_sync内核进程
  35. sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
  36. if (sys_sync_work_queue == NULL) {
  37. pr_err ("fs_sync workqueue create failed.\n");
  38. }
  39. // 创建suspend内核进程
  40. suspend_work_queue = create_singlethread_workqueue("suspend");
  41. if (suspend_work_queue == NULL) {
  42. ret = -ENOMEM;
  43. goto err_suspend_work_queue;
  44. }
  45. #ifdef CONFIG_WAKELOCK_STAT
  46. // 在proc下创建wakelocks文件
  47. proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
  48. #endif
  49. return 0;
  50. err_suspend_work_queue:
  51. platform_driver_unregister(&power_driver);
  52. err_platform_driver_register:
  53. platform_device_unregister(&power_device);
  54. err_platform_device_register:
  55. wake_lock_destroy(&unknown_wakeup);
  56. wake_lock_destroy(&main_wake_lock);
  57. #ifdef CONFIG_WAKELOCK_STAT
  58. wake_lock_destroy(&deleted_wake_locks);
  59. #endif
  60. return ret;
  61. }
  62. 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初始化

  1. void wake_lock_init(struct wake_lock *lock, int type, const char *name)
  2. {
  3. unsigned long irqflags = 0;
  4. // 初始化名称
  5. if (name)
  6. lock->name = name;
  7. BUG_ON(!lock->name);
  8. if (debug_mask & DEBUG_WAKE_LOCK)
  9. pr_info("wake_lock_init name=%s\n", lock->name);
  10. #ifdef CONFIG_WAKELOCK_STAT
  11. lock->stat.count = 0;
  12. lock->stat.expire_count = 0;
  13. lock->stat.wakeup_count = 0;
  14. lock->stat.total_time = ktime_set(0, 0);
  15. lock->stat.prevent_suspend_time = ktime_set(0, 0);
  16. lock->stat.max_time = ktime_set(0, 0);
  17. lock->stat.last_time = ktime_set(0, 0);
  18. #endif
  19. // 初始化flag
  20. lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
  21. // 初始化链表节点
  22. INIT_LIST_HEAD(&lock->link);
  23. spin_lock_irqsave(&list_lock, irqflags);
  24. // 将锁加入无效锁链表
  25. list_add(&lock->link, &inactive_locks);
  26. spin_unlock_irqrestore(&list_lock, irqflags);
  27. }
  28. 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()激活该锁:

  1. // 根据参数激活锁
  2. static void wake_lock_internal(
  3. struct wake_lock *lock, long timeout, int has_timeout)
  4. {
  5. int type;
  6. unsigned long irqflags;
  7. long expire_in;
  8. spin_lock_irqsave(&list_lock, irqflags);
  9. // 获取锁的类型
  10. type = lock->flags & WAKE_LOCK_TYPE_MASK;
  11. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
  12. BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
  13. #ifdef CONFIG_WAKELOCK_STAT
  14. if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
  15. if (debug_mask & DEBUG_WAKEUP)
  16. pr_info("wakeup wake lock: %s\n", lock->name);
  17. wait_for_wakeup = 0;
  18. lock->stat.wakeup_count++;
  19. }
  20. if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
  21. (long)(lock->expires - jiffies) <= 0) {
  22. wake_unlock_stat_locked(lock, 0);
  23. lock->stat.last_time = ktime_get();
  24. }
  25. #endif
  26. // 设置锁有效的标志位
  27. if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
  28. lock->flags |= WAKE_LOCK_ACTIVE;
  29. #ifdef CONFIG_WAKELOCK_STAT
  30. lock->stat.last_time = ktime_get();
  31. #endif
  32. }
  33. // 将锁从无效锁链表中删除
  34. list_del(&lock->link);
  35. // 如果是超时锁
  36. if (has_timeout) {
  37. if (debug_mask & DEBUG_WAKE_LOCK)
  38. pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
  39. lock->name, type, timeout / HZ,
  40. (timeout % HZ) * MSEC_PER_SEC / HZ);
  41. // 设置锁超时时间,以当前jiffies为基准
  42. lock->expires = jiffies + timeout;
  43. // 设置锁的超时锁标志
  44. lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
  45. // 将锁加入有效锁链表
  46. list_add_tail(&lock->link, &active_wake_locks[type]);
  47. } else {  // 如果是永久锁
  48. if (debug_mask & DEBUG_WAKE_LOCK)
  49. pr_info("wake_lock: %s, type %d\n", lock->name, type);
  50. // 设置超时时间为极限
  51. lock->expires = LONG_MAX;
  52. // 清除超时锁标志
  53. lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
  54. // 将锁加入有效锁链表
  55. list_add(&lock->link, &active_wake_locks[type]);
  56. }
  57. // 如果是休眠锁
  58. if (type == WAKE_LOCK_SUSPEND) {
  59. current_event_num++;  // 休眠锁使用计数器加1
  60. #ifdef CONFIG_WAKELOCK_STAT
  61. // 如果是内核休眠锁
  62. if (lock == &main_wake_lock)
  63. update_sleep_wait_stats_locked(1);
  64. // 如果内核休眠锁无效
  65. else if (!wake_lock_active(&main_wake_lock))
  66. update_sleep_wait_stats_locked(0);
  67. #endif
  68. // 如果是超时锁
  69. if (has_timeout)
  70. expire_in = has_wake_lock_locked(type);
  71. else
  72. expire_in = -1;
  73. // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in
  74. if (expire_in > 0) {
  75. if (debug_mask & DEBUG_EXPIRE)
  76. pr_info("wake_lock: %s, start expire timer, "
  77. "%ld\n", lock->name, expire_in);
  78. mod_timer(&expire_timer, jiffies + expire_in);
  79. } else {  // 如果有永久锁或者无有效锁
  80. if (del_timer(&expire_timer))
  81. if (debug_mask & DEBUG_EXPIRE)
  82. pr_info("wake_lock: %s, stop expire timer\n",
  83. lock->name);
  84. if (expire_in == 0)  // 无有效锁
  85. queue_work(suspend_work_queue, &suspend_work);
  86. }
  87. }
  88. spin_unlock_irqrestore(&list_lock, irqflags);
  89. }
  90. // 激活永久锁
  91. void wake_lock(struct wake_lock *lock)
  92. {
  93. wake_lock_internal(lock, 0, 0);
  94. }
  95. EXPORT_SYMBOL(wake_lock);
  96. // 激活超时锁
  97. void wake_lock_timeout(struct wake_lock *lock, long timeout)
  98. {
  99. wake_lock_internal(lock, timeout, 1);
  100. }
  101. 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

  1. static void expire_wake_locks(unsigned long data)
  2. {
  3. long has_lock;
  4. unsigned long irqflags;
  5. if (debug_mask & DEBUG_EXPIRE)
  6. pr_info("expire_wake_locks: start\n");
  7. spin_lock_irqsave(&list_lock, irqflags);
  8. // 打印当前的有效锁
  9. if (debug_mask & DEBUG_SUSPEND)
  10. print_active_locks(WAKE_LOCK_SUSPEND);
  11. // 检测系统是否持有休眠锁
  12. has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
  13. if (debug_mask & DEBUG_EXPIRE)
  14. pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
  15. // 如果系统当前没有持有有效地休眠锁
  16. if (has_lock == 0)
  17. // 则启动深度休眠工作队列
  18. queue_work(suspend_work_queue, &suspend_work);
  19. spin_unlock_irqrestore(&list_lock, irqflags);
  20. }
  21. // 定义timer,运行函数为expire_wake_locks
  22. 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

  1. static void suspend(struct work_struct *work)
  2. {
  3. int ret;
  4. int entry_event_num;
  5. // 判断系统是否还持有有效锁,如果有则直接返回
  6. if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
  7. if (debug_mask & DEBUG_SUSPEND)
  8. pr_info("suspend: abort suspend\n");
  9. return;
  10. }
  11. // 记录函数进入时休眠锁的使用次数
  12. entry_event_num = current_event_num;
  13. sys_sync();  // 将缓存中的数据写入磁盘
  14. if (debug_mask & DEBUG_SUSPEND)
  15. pr_info("suspend: enter suspend\n");
  16. // 开始深度休眠
  17. ret = pm_suspend(requested_suspend_state);
  18. // 退出深度休眠,打印信息
  19. if (debug_mask & DEBUG_EXIT_SUSPEND) {
  20. struct timespec ts;
  21. struct rtc_time tm;
  22. getnstimeofday(&ts);
  23. rtc_time_to_tm(ts.tv_sec, &tm);
  24. pr_info("suspend: exit suspend, ret = %d "
  25. "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
  26. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
  27. tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
  28. }
  29. // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁
  30. if (current_event_num == entry_event_num) {
  31. if (debug_mask & DEBUG_SUSPEND)
  32. pr_info("suspend: pm_suspend returned with no event\n");
  33. // 激活unknown_wakeup,0.5s超时
  34. wake_lock_timeout(&unknown_wakeup, HZ / 2);
  35. }
  36. }
  37. // 声明工作队列,运行函数为suspend
  38. 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

  1. // 移除过期超时锁
  2. static void expire_wake_lock(struct wake_lock *lock)
  3. {
  4. #ifdef CONFIG_WAKELOCK_STAT
  5. wake_unlock_stat_locked(lock, 1);
  6. #endif
  7. // 清除锁有效和超时锁标志
  8. lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
  9. // 从当前链表中删除
  10. list_del(&lock->link);
  11. // 加入无效锁链表
  12. list_add(&lock->link, &inactive_locks);
  13. if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
  14. pr_info("expired wake lock %s\n", lock->name);
  15. }
  16. // 打印有效锁信息,调用者需持有list_lock
  17. static void print_active_locks(int type)
  18. {
  19. struct wake_lock *lock;
  20. bool print_expired = true;
  21. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
  22. // 遍历有效锁链表
  23. list_for_each_entry(lock, &active_wake_locks[type], link) {
  24. // 如果是超时锁
  25. if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
  26. // 计算超时剩余时间
  27. long timeout = lock->expires - jiffies;
  28. if (timeout > 0)
  29. pr_info("active wake lock %s, time left %ld\n",
  30. lock->name, timeout);
  31. else if (print_expired)
  32. pr_info("wake lock %s, expired\n", lock->name);
  33. } else {  // 如果不是超时锁
  34. pr_info("active wake lock %s\n", lock->name);
  35. if (!debug_mask & DEBUG_EXPIRE)
  36. print_expired = false;
  37. }
  38. }
  39. }
  40. static long has_wake_lock_locked(int type)
  41. {
  42. struct wake_lock *lock, *n;
  43. long max_timeout = 0;
  44. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
  45. // 遍历有效锁链表
  46. list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
  47. // 如果是超时锁
  48. if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
  49. // 计算超时剩余时间
  50. long timeout = lock->expires - jiffies;
  51. // 如果锁已经过期
  52. if (timeout <= 0)
  53. // 移除过期锁
  54. expire_wake_lock(lock);
  55. else if (timeout > max_timeout)  // 如果锁没有过期
  56. // 得到最长的一个超时时间
  57. max_timeout = timeout;
  58. } else // 如果不是超时锁则返回-1
  59. return -1;
  60. }
  61. return max_timeout;
  62. }
  63. // 判断系统是否还持有有效锁
  64. long has_wake_lock(int type)
  65. {
  66. long ret;
  67. unsigned long irqflags;
  68. spin_lock_irqsave(&list_lock, irqflags);
  69. // 开始判断流程
  70. ret = has_wake_lock_locked(type);
  71. // 如果还有休眠锁有效则打印状态信息
  72. if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
  73. print_active_locks(type);
  74. spin_unlock_irqrestore(&list_lock, irqflags);
  75. return ret;
  76. }
<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

  1. void wake_unlock(struct wake_lock *lock)
  2. {
  3. int type;
  4. unsigned long irqflags;
  5. spin_lock_irqsave(&list_lock, irqflags);
  6. type = lock->flags & WAKE_LOCK_TYPE_MASK;
  7. #ifdef CONFIG_WAKELOCK_STAT
  8. // 更新锁的状态
  9. wake_unlock_stat_locked(lock, 0);
  10. #endif
  11. if (debug_mask & DEBUG_WAKE_LOCK)
  12. pr_info("wake_unlock: %s\n", lock->name);
  13. // 清楚有效锁和超时锁标志
  14. lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
  15. // 将锁从有效锁链表中移除加入无效锁链表
  16. list_del(&lock->link);
  17. list_add(&lock->link, &inactive_locks);
  18. // 如果是休眠锁
  19. if (type == WAKE_LOCK_SUSPEND) {
  20. // 判断系统当前是否还持有锁
  21. long has_lock = has_wake_lock_locked(type);
  22. // 如果还持有锁,设置timer到超时时间点触发
  23. if (has_lock > 0) {
  24. if (debug_mask & DEBUG_EXPIRE)
  25. pr_info("wake_unlock: %s, start expire timer, "
  26. "%ld\n", lock->name, has_lock);
  27. mod_timer(&expire_timer, jiffies + has_lock);
  28. } else {
  29. if (del_timer(&expire_timer))  // 删除timer
  30. if (debug_mask & DEBUG_EXPIRE)
  31. pr_info("wake_unlock: %s, stop expire "
  32. "timer\n", lock->name);
  33. if (has_lock == 0)  // 启动深度休眠工作队列
  34. queue_work(suspend_work_queue, &suspend_work);
  35. }
  36. // 如果是内核锁
  37. if (lock == &main_wake_lock) {
  38. if (debug_mask & DEBUG_SUSPEND)
  39. // 打印当前有效锁信息
  40. print_active_locks(WAKE_LOCK_SUSPEND);
  41. #ifdef CONFIG_WAKELOCK_STAT
  42. update_sleep_wait_stats_locked(0);
  43. #endif
  44. }
  45. }
  46. spin_unlock_irqrestore(&list_lock, irqflags);
  47. }
  48. 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

  1. // 判断锁是否有效
  2. int wake_lock_active(struct wake_lock *lock)
  3. {
  4. return !!(lock->flags & WAKE_LOCK_ACTIVE);
  5. }
  6. 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

  1. void wake_lock_destroy(struct wake_lock *lock)
  2. {
  3. unsigned long irqflags;
  4. if (debug_mask & DEBUG_WAKE_LOCK)
  5. pr_info("wake_lock_destroy name=%s\n", lock->name);
  6. spin_lock_irqsave(&list_lock, irqflags);
  7. // 清除已经初始化的标志
  8. lock->flags &= ~WAKE_LOCK_INITIALIZED;
  9. #ifdef CONFIG_WAKELOCK_STAT
  10. if (lock->stat.count) {
  11. deleted_wake_locks.stat.count += lock->stat.count;
  12. deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
  13. deleted_wake_locks.stat.total_time =
  14. ktime_add(deleted_wake_locks.stat.total_time,
  15. lock->stat.total_time);
  16. deleted_wake_locks.stat.prevent_suspend_time =
  17. ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
  18. lock->stat.prevent_suspend_time);
  19. deleted_wake_locks.stat.max_time =
  20. ktime_add(deleted_wake_locks.stat.max_time,
  21. lock->stat.max_time);
  22. }
  23. #endif
  24. // 从当前链表中删除
  25. list_del(&lock->link);
  26. spin_unlock_irqrestore(&list_lock, irqflags);
  27. }
  28. 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节点

  1. // 获取锁的剩余超时时间,通过*expire_time传递
  2. int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
  3. {
  4. struct timespec ts;
  5. struct timespec kt;
  6. struct timespec tomono;
  7. struct timespec delta;
  8. unsigned long seq;
  9. long timeout;
  10. // 如果不是超时锁则直接返回
  11. if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
  12. return 0;
  13. do {
  14. seq = read_seqbegin(&xtime_lock);
  15. // 计算超时时间点与当前时间的差值
  16. timeout = lock->expires - jiffies;
  17. // 如果时间没有到期,返回0
  18. if (timeout > 0)
  19. return 0;
  20. // 获取当前时间
  21. kt = current_kernel_time();
  22. tomono = wall_to_monotonic;
  23. } while (read_seqretry(&xtime_lock, seq));
  24. // 时间格式转换
  25. jiffies_to_timespec(-timeout, &delta);
  26. // 设置timespec的成员
  27. set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
  28. kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
  29. // 返回ts值
  30. *expire_time = timespec_to_ktime(ts);
  31. return 1;
  32. }
  33. // 打印出锁的状态信息
  34. static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
  35. {
  36. int lock_count = lock->stat.count;
  37. int expire_count = lock->stat.expire_count;
  38. ktime_t active_time = ktime_set(0, 0);
  39. ktime_t total_time = lock->stat.total_time;
  40. ktime_t max_time = lock->stat.max_time;
  41. ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
  42. // 如果锁有效
  43. if (lock->flags & WAKE_LOCK_ACTIVE) {
  44. ktime_t now, add_time;
  45. // 获取超时剩余时间
  46. int expired = get_expired_time(lock, &now);
  47. if (!expired)
  48. now = ktime_get();
  49. // 计算当前时间和上次操作时间的差值
  50. add_time = ktime_sub(now, lock->stat.last_time);
  51. lock_count++;  // 使用计数加1
  52. if (!expired)  // 如果没有到期
  53. active_time = add_time;
  54. else  // 锁已经到期
  55. expire_count++;  // 超时计数加1
  56. total_time = ktime_add(total_time, add_time);  // 锁使用时间增加
  57. if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
  58. prevent_suspend_time = ktime_add(prevent_suspend_time,
  59. ktime_sub(now, last_sleep_time_update));
  60. if (add_time.tv64 > max_time.tv64)
  61. max_time = add_time;
  62. }
  63. return seq_printf(m,
  64. "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
  65. lock->name, lock_count, expire_count,
  66. lock->stat.wakeup_count, ktime_to_ns(active_time),
  67. ktime_to_ns(total_time),
  68. ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
  69. ktime_to_ns(lock->stat.last_time));
  70. }
  71. // 打印锁状态
  72. static int wakelock_stats_show(struct seq_file *m, void *unused)
  73. {
  74. unsigned long irqflags;
  75. struct wake_lock *lock;
  76. int ret;
  77. int type;
  78. spin_lock_irqsave(&list_lock, irqflags);
  79. // 输出菜单
  80. ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
  81. "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
  82. // 遍历无效锁链表并打印锁的状态信息
  83. list_for_each_entry(lock, &inactive_locks, link)
  84. ret = print_lock_stat(m, lock);
  85. // 遍历有效锁链表并打印锁的状态信息
  86. for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
  87. list_for_each_entry(lock, &active_wake_locks[type], link)
  88. ret = print_lock_stat(m, lock);
  89. }
  90. spin_unlock_irqrestore(&list_lock, irqflags);
  91. return 0;
  92. }
  93. // proc文件打开函数,调用show函数显示当前所有的锁信息
  94. static int wakelock_stats_open(struct inode *inode, struct file *file)
  95. {
  96. return single_open(file, wakelock_stats_show, NULL);
  97. }
  98. // proc文件系统操作函数
  99. static const struct file_operations wakelock_stats_fops = {
  100. .owner = THIS_MODULE,
  101. .open = wakelock_stats_open,
  102. .read = seq_read,
  103. .llseek = seq_lseek,
  104. .release = single_release,
  105. };
<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最常见。

(linux)wake_lock机制的更多相关文章

  1. Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...

  2. android & Linux uevent机制

    Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入.拔出,电池电量变化等等.其本质是内核发送(可以通过socket)一个字符串,应用层(andro ...

  3. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  4. Linux 内存机制详解宝典

    Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...

  5. Linux Namespaces机制——实现

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480573.html 由于Linux内核提供了PID,IPC,NS等多个Namespace ...

  6. Linux Namespaces机制

    转自:http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html Linux Namespaces机制提供一种资源隔离方案.PID,I ...

  7. Linux分页机制之概述--Linux内存管理(六)

    1 分页机制 在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(linear address)映射到存储器上的物理地址(phisical address). 很显然,这个页表是需要常驻内 ...

  8. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

  9. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

随机推荐

  1. 【JQ同胞遍历】

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. Linux(13):期中架构(5)--- 前端部分:keepalived高可用 & HTTPS & iptables防火墙

    keepalived 高可用集群 1. keepalived服务概念说明 # 1.1 keepalived软件的作用? Keepalived软件起初是专为LVS负载均衡软件设计的, 用来管理并监控LV ...

  3. 济南学习 Day 5 T1 am

    炮(cannon)[题目描述]众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技.炮吃子时必须隔一个棋子跳吃,即俗称“炮打隔子”. 炮跟炮显然不能在一起打起来,于是rly一天借来了许多许多的炮在棋盘上 ...

  4. form表单提交file

    form表单提交文件,这毫无疑问不是个好办法.但是,存在既有意义.既然H5都还让着东西存在着,呢么必然有其意义. form表单中的input type=file这个空间,不得不说奇丑无比!问题是还不能 ...

  5. R语言入门视频笔记--3--列表list

    list <- (stud.id = 1234,stud.name="Tom",stud,marks=c(18,3,14,25,19)) #生成一个列表,里面有学生id,学生 ...

  6. 动态添加radiogroup

    private LinearLayout layout; //布局 , 可以在xml布局中获得 private RadioGroup group ; //点选按钮组 public void onCre ...

  7. Android借助Handler,实现ViewPager中页面的自动切换(转)

    在很多电商网页及app上都有自动切换的商品的推广快,感觉体验挺不错的,正好今天学习使用ViewPager,因此也实现了一个功能类似的demo. 下面是其中的两个截图:           实现一个自动 ...

  8. 有向图tarjan算法求连通分量的粗浅讲解、证明, // hdu1269

    打算开始重新复习一遍相关算法.对于有向图tarjan算法,通过学习过很多说法,结合自己的理解,下面给出算法自己的观点. 算法总模型是一个dfs,结合一个stack(存放当前尚未形成SCC的点集合),记 ...

  9. SQL自动生成A到Z二十六个英文字母

    if object_id('#tempdriveinfo') is not null drop table #tempdriveinfo create table #tempdriveinfo ( [ ...

  10. PAT (Advanced Level) 1086. Tree Traversals Again (25)

    入栈顺序为先序遍历,出栈顺序为中序遍历. #include<cstdio> #include<cstring> #include<cmath> #include&l ...