• (linux)wake_lock机制


     

    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.   
    7. struct wake_lock {  
    8. #ifdef CONFIG_HAS_WAKELOCK  
    9.     struct list_head    link;     // 链表节点  
    10.     int                 flags;    // 标志  
    11.     const char         *name;     // 名称  
    12.     unsigned long       expires;  // 超时时间  
    13. #ifdef CONFIG_WAKELOCK_STAT  
    14.     struct {  
    15.         int             count;         // 使用计数  
    16.         int             expire_count;  // 超时计数  
    17.         int             wakeup_count;  // 唤醒计数  
    18.         ktime_t         total_time;    // 锁使用时间  
    19.         ktime_t         prevent_suspend_time;  // 锁阻止休眠的时间  
    20.         ktime_t         max_time;      // 锁使用时间最长的一次  
    21.         ktime_t         last_time;     // 锁上次操作时间  
    22.     } stat;  
    23. #endif  
    24. #endif  
    25. };  
    <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.   
    10.     mutex_lock(&tree_lock);  
    11.   
    12.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {  
    13.         l = rb_entry(n, struct user_wake_lock, node);  
    14.         if (wake_lock_active(&l->wake_lock))  
    15.             s += scnprintf(s, end - s, "%s ", l->name);  
    16.     }  
    17.     s += scnprintf(s, end - s, " ");  
    18.   
    19.     mutex_unlock(&tree_lock);  
    20.     return (s - buf);  
    21. }  
    22.   
    23. // wack_lock文件的写函数,初始化并激活用户空间定义的锁  
    24. ssize_t wake_lock_store(  
    25.     struct kobject *kobj, struct kobj_attribute *attr,  
    26.     const char *buf, size_t n)  
    27. {  
    28.     long timeout;  
    29.     struct user_wake_lock *l;  
    30.   
    31.     mutex_lock(&tree_lock);  
    32.     l = lookup_wake_lock_name(buf, 1, &timeout);  
    33.     if (IS_ERR(l)) {  
    34.         n = PTR_ERR(l);  
    35.         goto bad_name;  
    36.     }  
    37.   
    38.     if (debug_mask & DEBUG_ACCESS)  
    39.         pr_info("wake_lock_store: %s, timeout %ld ", l->name, timeout);  
    40.   
    41.     if (timeout)  
    42.         wake_lock_timeout(&l->wake_lock, timeout);  
    43.     else  
    44.         wake_lock(&l->wake_lock);  
    45. bad_name:  
    46.     mutex_unlock(&tree_lock);  
    47.     return n;  
    48. }  
    49.   
    50. // wack_unlock文件的读函数,显示用户空间的无效锁  
    51. ssize_t wake_unlock_show(  
    52.     struct kobject *kobj, struct kobj_attribute *attr, char *buf)  
    53. {  
    54.     char *s = buf;  
    55.     char *end = buf + PAGE_SIZE;  
    56.     struct rb_node *n;  
    57.     struct user_wake_lock *l;  
    58.   
    59.     mutex_lock(&tree_lock);  
    60.   
    61.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {  
    62.         l = rb_entry(n, struct user_wake_lock, node);  
    63.         if (!wake_lock_active(&l->wake_lock))  
    64.             s += scnprintf(s, end - s, "%s ", l->name);  
    65.     }  
    66.     s += scnprintf(s, end - s, " ");  
    67.   
    68.     mutex_unlock(&tree_lock);  
    69.     return (s - buf);  
    70. }  
    71.   
    72. // wack_unlock文件的写函数,用于用户空间解锁  
    73. ssize_t wake_unlock_store(  
    74.     struct kobject *kobj, struct kobj_attribute *attr,  
    75.     const char *buf, size_t n)  
    76. {  
    77.     struct user_wake_lock *l;  
    78.   
    79.     mutex_lock(&tree_lock);  
    80.     l = lookup_wake_lock_name(buf, 0, NULL);  
    81.     if (IS_ERR(l)) {  
    82.         n = PTR_ERR(l);  
    83.         goto not_found;  
    84.     }  
    85.   
    86.     if (debug_mask & DEBUG_ACCESS)  
    87.         pr_info("wake_unlock_store: %s ", l->name);  
    88.   
    89.     wake_unlock(&l->wake_lock);  
    90. not_found:  
    91.     mutex_unlock(&tree_lock);  
    92.     return n;  
    93. }  
    94.   
    95. power_attr(wake_lock);  
    96. 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, "
    ");
    
    	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
    ", 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, "
    ");
    
    	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
    ", 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.   
    7. static DEFINE_SPINLOCK(list_lock);  // 读写锁链表的自旋锁  
    8. static LIST_HEAD(inactive_locks);   // 内核维护的无效锁链表  
    9. static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];  // 有效锁链表  
    10. static int current_event_num;       // 休眠锁使用计数器  
    11. struct workqueue_struct *suspend_work_queue;  // 执行系统休眠的工作队列  
    12. struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列  
    13. struct wake_lock main_wake_lock;              // 内核休眠锁  
    14. struct wake_lock sys_sync_wake_lock;          // 缓存同步锁  
    15. suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;  // 系统休眠状态  
    16. 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.   
    11. #ifdef CONFIG_WAKELOCK_STAT  
    12.     // 初始化deleted_wake_locks  
    13.     wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,  
    14.             "deleted_wake_locks");  
    15. #endif  
    16.     // 初始化内核休眠锁  
    17.     wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");  
    18.     // 初始化同步锁  
    19.     wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");  
    20.     // 激活内核休眠锁  
    21.     wake_lock(&main_wake_lock);  
    22.     // 初始化未知锁  
    23.     wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");  
    24.   
    25.     // 注册power_device,power_driver  
    26.     ret = platform_device_register(&power_device);  
    27.     if (ret) {  
    28.         pr_err("wakelocks_init: platform_device_register failed ");  
    29.         goto err_platform_device_register;  
    30.     }  
    31.     ret = platform_driver_register(&power_driver);  
    32.     if (ret) {  
    33.         pr_err("wakelocks_init: platform_driver_register failed ");  
    34.         goto err_platform_driver_register;  
    35.     }  
    36.     // 创建fs_sync内核进程  
    37.     sys_sync_work_queue = create_singlethread_workqueue("fs_sync");  
    38.     if (sys_sync_work_queue == NULL) {  
    39.         pr_err ("fs_sync workqueue create failed. ");  
    40.     }  
    41.     // 创建suspend内核进程  
    42.     suspend_work_queue = create_singlethread_workqueue("suspend");  
    43.     if (suspend_work_queue == NULL) {  
    44.         ret = -ENOMEM;  
    45.         goto err_suspend_work_queue;  
    46.     }  
    47.   
    48. #ifdef CONFIG_WAKELOCK_STAT  
    49.     // 在proc下创建wakelocks文件  
    50.     proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);  
    51. #endif  
    52.   
    53.     return 0;  
    54.   
    55. err_suspend_work_queue:  
    56.     platform_driver_unregister(&power_driver);  
    57. err_platform_driver_register:  
    58.     platform_device_unregister(&power_device);  
    59. err_platform_device_register:  
    60.     wake_lock_destroy(&unknown_wakeup);  
    61.     wake_lock_destroy(&main_wake_lock);  
    62. #ifdef CONFIG_WAKELOCK_STAT  
    63.     wake_lock_destroy(&deleted_wake_locks);  
    64. #endif  
    65.     return ret;  
    66. }  
    67. 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
    ");
    		goto err_platform_device_register;
    	}
    	ret = platform_driver_register(&power_driver);
    	if (ret) {
    		pr_err("wakelocks_init: platform_driver_register failed
    ");
    		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.
    ");
    	}
    	// 创建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.   
    9.     if (debug_mask & DEBUG_WAKE_LOCK)  
    10.         pr_info("wake_lock_init name=%s ", lock->name);  
    11. #ifdef CONFIG_WAKELOCK_STAT  
    12.     lock->stat.count = 0;  
    13.     lock->stat.expire_count = 0;  
    14.     lock->stat.wakeup_count = 0;  
    15.     lock->stat.total_time = ktime_set(0, 0);  
    16.     lock->stat.prevent_suspend_time = ktime_set(0, 0);  
    17.     lock->stat.max_time = ktime_set(0, 0);  
    18.     lock->stat.last_time = ktime_set(0, 0);  
    19. #endif  
    20.     // 初始化flag  
    21.     lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;  
    22.     // 初始化链表节点  
    23.     INIT_LIST_HEAD(&lock->link);  
    24.     spin_lock_irqsave(&list_lock, irqflags);  
    25.     // 将锁加入无效锁链表  
    26.     list_add(&lock->link, &inactive_locks);  
    27.     spin_unlock_irqrestore(&list_lock, irqflags);  
    28. }  
    29. 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
    ", 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.   
    9.     spin_lock_irqsave(&list_lock, irqflags);  
    10.     // 获取锁的类型  
    11.     type = lock->flags & WAKE_LOCK_TYPE_MASK;  
    12.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);  
    13.     BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));  
    14. #ifdef CONFIG_WAKELOCK_STAT  
    15.     if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {  
    16.         if (debug_mask & DEBUG_WAKEUP)  
    17.             pr_info("wakeup wake lock: %s ", lock->name);  
    18.         wait_for_wakeup = 0;  
    19.         lock->stat.wakeup_count++;  
    20.     }  
    21.     if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&  
    22.         (long)(lock->expires - jiffies) <= 0) {  
    23.         wake_unlock_stat_locked(lock, 0);  
    24.         lock->stat.last_time = ktime_get();  
    25.     }  
    26. #endif  
    27.     // 设置锁有效的标志位  
    28.     if (!(lock->flags & WAKE_LOCK_ACTIVE)) {  
    29.         lock->flags |= WAKE_LOCK_ACTIVE;  
    30. #ifdef CONFIG_WAKELOCK_STAT  
    31.         lock->stat.last_time = ktime_get();  
    32. #endif  
    33.     }  
    34.     // 将锁从无效锁链表中删除  
    35.     list_del(&lock->link);  
    36.     // 如果是超时锁  
    37.     if (has_timeout) {  
    38.         if (debug_mask & DEBUG_WAKE_LOCK)  
    39.             pr_info("wake_lock: %s, type %d, timeout %ld.%03lu ",  
    40.                 lock->name, type, timeout / HZ,  
    41.                 (timeout % HZ) * MSEC_PER_SEC / HZ);  
    42.         // 设置锁超时时间,以当前jiffies为基准  
    43.         lock->expires = jiffies + timeout;  
    44.         // 设置锁的超时锁标志  
    45.         lock->flags |= WAKE_LOCK_AUTO_EXPIRE;  
    46.         // 将锁加入有效锁链表  
    47.         list_add_tail(&lock->link, &active_wake_locks[type]);  
    48.     } else {  // 如果是永久锁  
    49.         if (debug_mask & DEBUG_WAKE_LOCK)  
    50.             pr_info("wake_lock: %s, type %d ", lock->name, type);  
    51.         // 设置超时时间为极限  
    52.         lock->expires = LONG_MAX;  
    53.         // 清除超时锁标志  
    54.         lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;  
    55.         // 将锁加入有效锁链表  
    56.         list_add(&lock->link, &active_wake_locks[type]);  
    57.     }  
    58.     // 如果是休眠锁  
    59.     if (type == WAKE_LOCK_SUSPEND) {  
    60.         current_event_num++;  // 休眠锁使用计数器加1  
    61. #ifdef CONFIG_WAKELOCK_STAT  
    62.         // 如果是内核休眠锁  
    63.         if (lock == &main_wake_lock)  
    64.             update_sleep_wait_stats_locked(1);  
    65.         // 如果内核休眠锁无效  
    66.         else if (!wake_lock_active(&main_wake_lock))  
    67.             update_sleep_wait_stats_locked(0);  
    68. #endif  
    69.         // 如果是超时锁  
    70.         if (has_timeout)  
    71.             expire_in = has_wake_lock_locked(type);  
    72.         else  
    73.             expire_in = -1;  
    74.         // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in  
    75.         if (expire_in > 0) {  
    76.             if (debug_mask & DEBUG_EXPIRE)  
    77.                 pr_info("wake_lock: %s, start expire timer, "  
    78.                     "%ld ", lock->name, expire_in);  
    79.             mod_timer(&expire_timer, jiffies + expire_in);  
    80.         } else {  // 如果有永久锁或者无有效锁  
    81.             if (del_timer(&expire_timer))  
    82.                 if (debug_mask & DEBUG_EXPIRE)  
    83.                     pr_info("wake_lock: %s, stop expire timer ",  
    84.                         lock->name);  
    85.             if (expire_in == 0)  // 无有效锁  
    86.                 queue_work(suspend_work_queue, &suspend_work);  
    87.         }  
    88.     }  
    89.     spin_unlock_irqrestore(&list_lock, irqflags);  
    90. }  
    91.   
    92. // 激活永久锁  
    93. void wake_lock(struct wake_lock *lock)  
    94. {  
    95.     wake_lock_internal(lock, 0, 0);  
    96. }  
    97. EXPORT_SYMBOL(wake_lock);  
    98.   
    99. // 激活超时锁  
    100. void wake_lock_timeout(struct wake_lock *lock, long timeout)  
    101. {  
    102.     wake_lock_internal(lock, timeout, 1);  
    103. }  
    104. 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
    ", 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
    ",
    				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
    ", 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
    ", 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
    ",
    						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 ");  
    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 ", 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
    ");
    	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
    ", 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.     // 判断系统是否还持有有效锁,如果有则直接返回  
    7.     if (has_wake_lock(WAKE_LOCK_SUSPEND)) {  
    8.         if (debug_mask & DEBUG_SUSPEND)  
    9.             pr_info("suspend: abort suspend ");  
    10.         return;  
    11.     }  
    12.   
    13.     // 记录函数进入时休眠锁的使用次数  
    14.     entry_event_num = current_event_num;  
    15.     sys_sync();  // 将缓存中的数据写入磁盘  
    16.     if (debug_mask & DEBUG_SUSPEND)  
    17.         pr_info("suspend: enter suspend ");  
    18.     // 开始深度休眠  
    19.     ret = pm_suspend(requested_suspend_state);  
    20.     // 退出深度休眠,打印信息  
    21.     if (debug_mask & DEBUG_EXIT_SUSPEND) {  
    22.         struct timespec ts;  
    23.         struct rtc_time tm;  
    24.         getnstimeofday(&ts);  
    25.         rtc_time_to_tm(ts.tv_sec, &tm);  
    26.         pr_info("suspend: exit suspend, ret = %d "  
    27.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC) ", ret,  
    28.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
    29.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
    30.     }  
    31.     // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁  
    32.     if (current_event_num == entry_event_num) {  
    33.         if (debug_mask & DEBUG_SUSPEND)  
    34.             pr_info("suspend: pm_suspend returned with no event ");  
    35.         // 激活unknown_wakeup,0.5s超时  
    36.         wake_lock_timeout(&unknown_wakeup, HZ / 2);  
    37.     }  
    38. }  
    39. // 声明工作队列,运行函数为suspend  
    40. 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
    ");
    		return;
    	}
    
    	// 记录函数进入时休眠锁的使用次数
    	entry_event_num = current_event_num;
    	sys_sync();  // 将缓存中的数据写入磁盘
    	if (debug_mask & DEBUG_SUSPEND)
    		pr_info("suspend: enter suspend
    ");
    	// 开始深度休眠
    	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)
    ", 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
    ");
    		// 激活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 ", lock->name);  
    15. }  
    16.   
    17. // 打印有效锁信息,调用者需持有list_lock  
    18. static void print_active_locks(int type)  
    19. {  
    20.     struct wake_lock *lock;  
    21.     bool print_expired = true;  
    22.   
    23.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);  
    24.     // 遍历有效锁链表  
    25.     list_for_each_entry(lock, &active_wake_locks[type], link) {  
    26.         // 如果是超时锁  
    27.         if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {  
    28.             // 计算超时剩余时间  
    29.             long timeout = lock->expires - jiffies;  
    30.             if (timeout > 0)  
    31.                 pr_info("active wake lock %s, time left %ld ",  
    32.                     lock->name, timeout);  
    33.             else if (print_expired)  
    34.                 pr_info("wake lock %s, expired ", lock->name);  
    35.         } else {  // 如果不是超时锁  
    36.             pr_info("active wake lock %s ", lock->name);  
    37.             if (!debug_mask & DEBUG_EXPIRE)  
    38.                 print_expired = false;  
    39.         }  
    40.     }  
    41. }  
    42.   
    43. static long has_wake_lock_locked(int type)  
    44. {  
    45.     struct wake_lock *lock, *n;  
    46.     long max_timeout = 0;  
    47.   
    48.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);  
    49.     // 遍历有效锁链表  
    50.     list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {  
    51.         // 如果是超时锁  
    52.         if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {  
    53.             // 计算超时剩余时间  
    54.             long timeout = lock->expires - jiffies;  
    55.             // 如果锁已经过期  
    56.             if (timeout <= 0)  
    57.                 // 移除过期锁  
    58.                 expire_wake_lock(lock);  
    59.             else if (timeout > max_timeout)  // 如果锁没有过期  
    60.                 // 得到最长的一个超时时间  
    61.                 max_timeout = timeout;  
    62.         } else // 如果不是超时锁则返回-1  
    63.             return -1;  
    64.     }  
    65.     return max_timeout;  
    66. }  
    67.   
    68. // 判断系统是否还持有有效锁  
    69. long has_wake_lock(int type)  
    70. {  
    71.     long ret;  
    72.     unsigned long irqflags;  
    73.     spin_lock_irqsave(&list_lock, irqflags);  
    74.     // 开始判断流程  
    75.     ret = has_wake_lock_locked(type);  
    76.     // 如果还有休眠锁有效则打印状态信息  
    77.     if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)  
    78.         print_active_locks(type);  
    79.     spin_unlock_irqrestore(&list_lock, irqflags);  
    80.     return ret;  
    81. }  
    <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
    ", 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
    ",
    					lock->name, timeout);
    			else if (print_expired)
    				pr_info("wake lock %s, expired
    ", lock->name);
    		} else {  // 如果不是超时锁
    			pr_info("active wake lock %s
    ", 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 ", 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 ", 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 ", 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
    ", 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
    ", 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
    ", 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 ", 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
    ", 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.     // 如果不是超时锁则直接返回  
    12.     if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))  
    13.         return 0;  
    14.   
    15.     do {  
    16.         seq = read_seqbegin(&xtime_lock);  
    17.         // 计算超时时间点与当前时间的差值  
    18.         timeout = lock->expires - jiffies;  
    19.         // 如果时间没有到期,返回0  
    20.         if (timeout > 0)  
    21.             return 0;  
    22.         // 获取当前时间  
    23.         kt = current_kernel_time();  
    24.         tomono = wall_to_monotonic;  
    25.     } while (read_seqretry(&xtime_lock, seq));  
    26.     // 时间格式转换  
    27.     jiffies_to_timespec(-timeout, &delta);  
    28.     // 设置timespec的成员  
    29.     set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,  
    30.                 kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);  
    31.     // 返回ts值  
    32.     *expire_time = timespec_to_ktime(ts);  
    33.     return 1;  
    34. }  
    35.   
    36. // 打印出锁的状态信息  
    37. static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)  
    38. {  
    39.     int lock_count = lock->stat.count;  
    40.     int expire_count = lock->stat.expire_count;  
    41.     ktime_t active_time = ktime_set(0, 0);  
    42.     ktime_t total_time = lock->stat.total_time;  
    43.     ktime_t max_time = lock->stat.max_time;  
    44.   
    45.     ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;  
    46.     // 如果锁有效  
    47.     if (lock->flags & WAKE_LOCK_ACTIVE) {  
    48.         ktime_t now, add_time;  
    49.         // 获取超时剩余时间  
    50.         int expired = get_expired_time(lock, &now);  
    51.         if (!expired)  
    52.             now = ktime_get();  
    53.         // 计算当前时间和上次操作时间的差值  
    54.         add_time = ktime_sub(now, lock->stat.last_time);  
    55.         lock_count++;  // 使用计数加1  
    56.         if (!expired)  // 如果没有到期  
    57.             active_time = add_time;  
    58.         else  // 锁已经到期  
    59.             expire_count++;  // 超时计数加1  
    60.         total_time = ktime_add(total_time, add_time);  // 锁使用时间增加  
    61.         if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)  
    62.             prevent_suspend_time = ktime_add(prevent_suspend_time,  
    63.                     ktime_sub(now, last_sleep_time_update));  
    64.         if (add_time.tv64 > max_time.tv64)  
    65.             max_time = add_time;  
    66.     }  
    67.   
    68.     return seq_printf(m,  
    69.              ""%s" %d %d %d %lld %lld %lld %lld %lld ",  
    70.              lock->name, lock_count, expire_count,  
    71.              lock->stat.wakeup_count, ktime_to_ns(active_time),  
    72.              ktime_to_ns(total_time),  
    73.              ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),  
    74.              ktime_to_ns(lock->stat.last_time));  
    75. }  
    76.   
    77. // 打印锁状态  
    78. static int wakelock_stats_show(struct seq_file *m, void *unused)  
    79. {  
    80.     unsigned long irqflags;  
    81.     struct wake_lock *lock;  
    82.     int ret;  
    83.     int type;  
    84.   
    85.     spin_lock_irqsave(&list_lock, irqflags);  
    86.     // 输出菜单  
    87.     ret = seq_puts(m, "name count expire_count wake_count active_since"  
    88.             " total_time sleep_time max_time last_change ");  
    89.     // 遍历无效锁链表并打印锁的状态信息  
    90.     list_for_each_entry(lock, &inactive_locks, link)  
    91.         ret = print_lock_stat(m, lock);  
    92.     // 遍历有效锁链表并打印锁的状态信息  
    93.     for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {  
    94.         list_for_each_entry(lock, &active_wake_locks[type], link)  
    95.             ret = print_lock_stat(m, lock);  
    96.     }  
    97.     spin_unlock_irqrestore(&list_lock, irqflags);  
    98.     return 0;  
    99. }  
    100.   
    101. // proc文件打开函数,调用show函数显示当前所有的锁信息  
    102. static int wakelock_stats_open(struct inode *inode, struct file *file)  
    103. {  
    104.     return single_open(file, wakelock_stats_show, NULL);  
    105. }  
    106.   
    107. // proc文件系统操作函数  
    108. static const struct file_operations wakelock_stats_fops = {  
    109.     .owner = THIS_MODULE,  
    110.     .open = wakelock_stats_open,  
    111.     .read = seq_read,  
    112.     .llseek = seq_lseek,  
    113.     .release = single_release,  
    114. };  
    <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"	%d	%d	%d	%lld	%lld	%lld	%lld	%lld
    ",
    		     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	count	expire_count	wake_count	active_since"
    			"	total_time	sleep_time	max_time	last_change
    ");
    	// 遍历无效锁链表并打印锁的状态信息
    	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最常见。

  • 相关阅读:
    课程作业四 生成随机数并求和,大数运算
    课程作业三 string,char操作
    课程作业二 类内静态内容(代码块,静态变量),构造函数,非静态代码块执行顺序
    十一作业 java数值范围方面训练
    课程作业一 将字符串型数组里的数字相加
    NABCD需求分析
    人月神话阅读笔记01
    软件工程第五周总结
    清明第三天
    清明第二天安排
  • 原文地址:https://www.cnblogs.com/yanghong-hnu/p/4671349.html
Copyright © 2020-2023  润新知