Android的休眠喚醒主要基於wake_lock機制,只要系統中存在任一有效的wake_lock,系統就不能進入深度休眠,但可以進行設備的淺度休眠操作。wake_lock一般在關閉lcd、tp但系統仍然需要正常運行的情況下使用,比如聽歌、傳輸很大的文件等。本文主要分析driver層wake_lock的實現。
一、wake_lock 定義和接口
- enum {
- WAKE_LOCK_SUSPEND, // 阻止進入深度休眠模式
- WAKE_LOCK_IDLE, // 阻止進入空閒模式
- WAKE_LOCK_TYPE_COUNT
- };
- struct wake_lock {
- #ifdef CONFIG_HAS_WAKELOCK
- struct list_head link; // 鏈表節點
- int flags; // 標誌
- const char *name; // 名稱
- unsigned long expires; // 超時時間
- #ifdef CONFIG_WAKELOCK_STAT
- struct {
- int count; // 使用計數
- int expire_count; // 超時計數
- int wakeup_count; // 喚醒計數
- ktime_t total_time; // 鎖使用時間
- ktime_t prevent_suspend_time; // 鎖阻止休眠的時間
- ktime_t max_time; // 鎖使用時間最長的一次
- ktime_t last_time; // 鎖上次操作時間
- } stat;
- #endif
- #endif
- };
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
};
可以看到wake_lock按功能分爲休眠鎖和空閒鎖兩種類型,用於阻止系統進入深度休眠模式或者空閒模式。wake_lock的主要部件有鎖名稱、鏈表節點、標誌位、超時時間,另外還有一個內嵌的結構用於統計鎖的使用信息。接下來我們看看wake_lock對外提供的操作接口:
1、內核空間接口
- void wake_lock_init(struct wake_lock *lock, int type, const char *name);
- void wake_lock_destroy(struct wake_lock *lock);
- void wake_lock(struct wake_lock *lock);
- void wake_lock_timeout(struct wake_lock *lock, long timeout);
- void wake_unlock(struct wake_lock *lock);
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);
其中wake_lock_init()用於初始化一個新鎖,type參數指定了鎖的類型;wake_lock_destroy()則註銷一個鎖;wake_lock()和wake_lock_timeout()用於將初始化完成的鎖激活,使之成爲有效的永久鎖或者超時鎖;wake_unlock()用於解鎖使之成爲無效鎖。另外還有兩個接口:
int wake_lock_active(struct wake_lock *lock);
long has_wake_lock(int type);
其中wake_lock_active()用於判斷鎖當前是否有效,如果有效則返回非0值;has_wake_lock()用於判斷系統中是否還存在有效的type型鎖,如果存在超時鎖則返回最長的一個鎖的超時時間,如果存在永久鎖則返回-1,如果系統中不存在有效鎖則返回0。
2、用戶空間接口
wake_lock向用戶空間提供了兩個文件節點用於申請鎖和解鎖:
- // wack_lock文件的讀函數,顯示用戶空間定義的有效鎖
- ssize_t wake_lock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_lock文件的寫函數,初始化並激活用戶空間定義的鎖
- ssize_t wake_lock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- long timeout;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 1, &timeout);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto bad_name;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
- if (timeout)
- wake_lock_timeout(&l->wake_lock, timeout);
- else
- wake_lock(&l->wake_lock);
- bad_name:
- mutex_unlock(&tree_lock);
- return n;
- }
- // wack_unlock文件的讀函數,顯示用戶空間的無效鎖
- ssize_t wake_unlock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (!wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_unlock文件的寫函數,用於用戶空間解鎖
- ssize_t wake_unlock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 0, NULL);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto not_found;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_unlock_store: %s\n", l->name);
- wake_unlock(&l->wake_lock);
- not_found:
- mutex_unlock(&tree_lock);
- return n;
- }
- power_attr(wake_lock);
- power_attr(wake_unlock);
// 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);
這兩個文件節點分別爲"/sys/power/wake_lock"和"/sys/power/wake_unlock",應用程序可以根據HAL層的接口讀寫這兩個節點。二、wake_lock 實現
在linux/kernel/power/wakelock.c中我們可以看到wake_lock的實現代碼,首先看看其定義的一些初始化信息:
- #define WAKE_LOCK_TYPE_MASK (0x0f) // 鎖類型標誌掩碼
- #define WAKE_LOCK_INITIALIZED (1U << 8) // 鎖已經初始化標誌
- #define WAKE_LOCK_ACTIVE (1U << 9) // 鎖有效標誌
- #define WAKE_LOCK_AUTO_EXPIRE (1U << 10) // 超時鎖標誌
- #define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11) // 正在阻止休眠標誌
- static DEFINE_SPINLOCK(list_lock); // 讀寫鎖鏈表的自旋鎖
- static LIST_HEAD(inactive_locks); // 內核維護的無效鎖鏈表
- static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT]; // 有效鎖鏈表
- static int current_event_num; // 休眠鎖使用計數器
- struct workqueue_struct *suspend_work_queue; // 執行系統休眠的工作隊列
- struct workqueue_struct *sys_sync_work_queue; // 執行系統同步的工作隊列
- struct wake_lock main_wake_lock; // 內核休眠鎖
- struct wake_lock sys_sync_wake_lock; // 緩存同步鎖
- suspend_state_t requested_suspend_state = PM_SUSPEND_MEM; // 系統休眠狀態
- static struct wake_lock unknown_wakeup; // 未知鎖
#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; // 未知鎖
在後面的分析中我們會看到這些變量的具體用途。
1、wake_lock系統初始化
- static int __init wakelocks_init(void)
- {
- int ret;
- int i;
- // 初始化有效鎖鏈表,內核維護了2個有效鎖鏈表
- // WAKE_LOCK_SUSPEND 用於阻止進入深度休眠模式
- // WAKE_LOCK_IDLE 用於阻止進入空閒模式
- for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
- INIT_LIST_HEAD(&active_wake_locks[i]);
- #ifdef CONFIG_WAKELOCK_STAT
- // 初始化deleted_wake_locks
- wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
- "deleted_wake_locks");
- #endif
- // 初始化內核休眠鎖
- wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
- // 初始化同步鎖
- wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
- // 激活內核休眠鎖
- wake_lock(&main_wake_lock);
- // 初始化未知鎖
- wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
- // 註冊power_device,power_driver
- ret = platform_device_register(&power_device);
- if (ret) {
- pr_err("wakelocks_init: platform_device_register failed\n");
- goto err_platform_device_register;
- }
- ret = platform_driver_register(&power_driver);
- if (ret) {
- pr_err("wakelocks_init: platform_driver_register failed\n");
- goto err_platform_driver_register;
- }
- // 創建fs_sync內核進程
- sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
- if (sys_sync_work_queue == NULL) {
- pr_err ("fs_sync workqueue create failed.\n");
- }
- // 創建suspend內核進程
- suspend_work_queue = create_singlethread_workqueue("suspend");
- if (suspend_work_queue == NULL) {
- ret = -ENOMEM;
- goto err_suspend_work_queue;
- }
- #ifdef CONFIG_WAKELOCK_STAT
- // 在proc下創建wakelocks文件
- proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
- #endif
- return 0;
- err_suspend_work_queue:
- platform_driver_unregister(&power_driver);
- err_platform_driver_register:
- platform_device_unregister(&power_device);
- err_platform_device_register:
- wake_lock_destroy(&unknown_wakeup);
- wake_lock_destroy(&main_wake_lock);
- #ifdef CONFIG_WAKELOCK_STAT
- wake_lock_destroy(&deleted_wake_locks);
- #endif
- return ret;
- }
- core_initcall(wakelocks_init);
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);
可以看到內核通過core_initcall調用了wake_lock系統的初始化函數,函數首先初始化了兩個有效鎖的鏈表,用於管理系統中的有效鎖;接下來初始化了deleted_wake_locks用於處理統計信息,main_wake_lock用於鎖定內核(系統啓動時會激活這個鎖,深度休眠時需要釋放這個鎖),sys_sync_wake_lock用於淺度休眠階段同步緩存時阻止內核進入深度休眠,unknown_wakeup用於喚醒時延遲0.5s進入下一次可能的深度休眠;還註冊了一個platform_device用於深度休眠階段檢測是否存在有效鎖;後面創建了內核進程fs_sync用於淺度休眠階段同步緩存,內核進程suspend用於進行淺度休眠和深度休眠;還在/proc下面創建了wakelocks節點用於顯示wake_lock的統計信息。
2、wake_lock初始化
- void wake_lock_init(struct wake_lock *lock, int type, const char *name)
- {
- unsigned long irqflags = 0;
- // 初始化名稱
- if (name)
- lock->name = name;
- BUG_ON(!lock->name);
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock_init name=%s\n", lock->name);
- #ifdef CONFIG_WAKELOCK_STAT
- lock->stat.count = 0;
- lock->stat.expire_count = 0;
- lock->stat.wakeup_count = 0;
- lock->stat.total_time = ktime_set(0, 0);
- lock->stat.prevent_suspend_time = ktime_set(0, 0);
- lock->stat.max_time = ktime_set(0, 0);
- lock->stat.last_time = ktime_set(0, 0);
- #endif
- // 初始化flag
- lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
- // 初始化鏈表節點
- INIT_LIST_HEAD(&lock->link);
- spin_lock_irqsave(&list_lock, irqflags);
- // 將鎖加入無效鎖鏈表
- list_add(&lock->link, &inactive_locks);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_lock_init);
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);
其中參數lock爲被初始化對象,type代表鎖的類型,name表示鎖的名稱, 函數主要初始化鎖的名稱並設置 WAKE_LOCK_INITIALIZED 標誌位,並將鎖加入無效鎖鏈表inactive_locks,當需要使用鎖的時候通過wake_lock()或者wake_lock_timeout()激活該鎖:
- // 根據參數激活鎖
- static void wake_lock_internal(
- struct wake_lock *lock, long timeout, int has_timeout)
- {
- int type;
- unsigned long irqflags;
- long expire_in;
- spin_lock_irqsave(&list_lock, irqflags);
- // 獲取鎖的類型
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
- #ifdef CONFIG_WAKELOCK_STAT
- if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
- if (debug_mask & DEBUG_WAKEUP)
- pr_info("wakeup wake lock: %s\n", lock->name);
- wait_for_wakeup = 0;
- lock->stat.wakeup_count++;
- }
- if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
- (long)(lock->expires - jiffies) <= 0) {
- wake_unlock_stat_locked(lock, 0);
- lock->stat.last_time = ktime_get();
- }
- #endif
- // 設置鎖有效的標誌位
- if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
- lock->flags |= WAKE_LOCK_ACTIVE;
- #ifdef CONFIG_WAKELOCK_STAT
- lock->stat.last_time = ktime_get();
- #endif
- }
- // 將鎖從無效鎖鏈表中刪除
- list_del(&lock->link);
- // 如果是超時鎖
- if (has_timeout) {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
- lock->name, type, timeout / HZ,
- (timeout % HZ) * MSEC_PER_SEC / HZ);
- // 設置鎖超時時間,以當前jiffies爲基準
- lock->expires = jiffies + timeout;
- // 設置鎖的超時鎖標誌
- lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
- // 將鎖加入有效鎖鏈表
- list_add_tail(&lock->link, &active_wake_locks[type]);
- } else { // 如果是永久鎖
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d\n", lock->name, type);
- // 設置超時時間爲極限
- lock->expires = LONG_MAX;
- // 清除超時鎖標誌
- lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
- // 將鎖加入有效鎖鏈表
- list_add(&lock->link, &active_wake_locks[type]);
- }
- // 如果是休眠鎖
- if (type == WAKE_LOCK_SUSPEND) {
- current_event_num++; // 休眠鎖使用計數器加1
- #ifdef CONFIG_WAKELOCK_STAT
- // 如果是內核休眠鎖
- if (lock == &main_wake_lock)
- update_sleep_wait_stats_locked(1);
- // 如果內核休眠鎖無效
- else if (!wake_lock_active(&main_wake_lock))
- update_sleep_wait_stats_locked(0);
- #endif
- // 如果是超時鎖
- if (has_timeout)
- expire_in = has_wake_lock_locked(type);
- else
- expire_in = -1;
- // 當前存在有效超時鎖,並且最長的一個到期時間間隔爲expire_in
- if (expire_in > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, start expire timer, "
- "%ld\n", lock->name, expire_in);
- mod_timer(&expire_timer, jiffies + expire_in);
- } else { // 如果有永久鎖或者無有效鎖
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, stop expire timer\n",
- lock->name);
- if (expire_in == 0) // 無有效鎖
- queue_work(suspend_work_queue, &suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- // 激活永久鎖
- void wake_lock(struct wake_lock *lock)
- {
- wake_lock_internal(lock, 0, 0);
- }
- EXPORT_SYMBOL(wake_lock);
- // 激活超時鎖
- void wake_lock_timeout(struct wake_lock *lock, long timeout)
- {
- wake_lock_internal(lock, timeout, 1);
- }
- EXPORT_SYMBOL(wake_lock_timeout);
// 根據參數激活鎖
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);
可以看到激活過程都是通過調用wake_lock_internal()完成的,該函數首先完成一些統計信息的初始化,設置 WAKE_LOCK_ACTIVE 標誌位並將鎖從無效鎖鏈表中移除;然後根據是否是超時鎖設置 WAKE_LOCK_AUTO_EXPIRE 標誌位,並設置超時鎖的超時時間,再將鎖加入有效鎖鏈表;最後再根據鎖的類型判斷是否爲休眠鎖,如果是休眠鎖且爲超時鎖則通過has_wake_lock_locked()獲取系統中存在的超時鎖中時間最長的到期時間值,並以此值設置expire_timer,has_wake_lock_locked()返回0則表示系統中不存在有效鎖則啓動suspend進程開始進入深度休眠狀態。
3、expire_timer
- static void expire_wake_locks(unsigned long data)
- {
- long has_lock;
- unsigned long irqflags;
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: start\n");
- spin_lock_irqsave(&list_lock, irqflags);
- // 打印當前的有效鎖
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- // 檢測系統是否持有休眠鎖
- has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
- // 如果系統當前沒有持有有效地休眠鎖
- if (has_lock == 0)
- // 則啓動深度休眠工作隊列
- queue_work(suspend_work_queue, &suspend_work);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- // 定義timer,運行函數爲expire_wake_locks
- static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
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);
該timer會在多個地方用到,在激活鎖的函數中註冊用於超時鎖到期後檢測系統的有效鎖狀態,如果系統不存在有效鎖了則啓動suspend進程。4、suspend_work
- static void suspend(struct work_struct *work)
- {
- int ret;
- int entry_event_num;
- // 判斷系統是否還持有有效鎖,如果有則直接返回
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
- // 記錄函數進入時休眠鎖的使用次數
- entry_event_num = current_event_num;
- sys_sync(); // 將緩存中的數據寫入磁盤
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- // 開始深度休眠
- ret = pm_suspend(requested_suspend_state);
- // 退出深度休眠,打印信息
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct timespec ts;
- struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
- }
- // 如果深度休眠前和深度休眠後鎖的使用次數一致,即喚醒過程中沒有激活新的鎖
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- // 激活unknown_wakeup,0.5s超時
- wake_lock_timeout(&unknown_wakeup, HZ / 2);
- }
- }
- // 聲明工作隊列,運行函數爲suspend
- static DECLARE_WORK(suspend_work, suspend);
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);
聲明工作隊列用於內核深度休眠,可以看到一個正常的休眠流程會三次調用sys_sync()用於同步緩存(之前一次在淺度休眠,之後一次在深度休眠),然後調用pm_suspend()開始執行深度休眠流程。5、has_wake_lock
- // 移除過期超時鎖
- static void expire_wake_lock(struct wake_lock *lock)
- {
- #ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 1);
- #endif
- // 清除鎖有效和超時鎖標誌
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- // 從當前鏈表中刪除
- list_del(&lock->link);
- // 加入無效鎖鏈表
- list_add(&lock->link, &inactive_locks);
- if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
- pr_info("expired wake lock %s\n", lock->name);
- }
- // 打印有效鎖信息,調用者需持有list_lock
- static void print_active_locks(int type)
- {
- struct wake_lock *lock;
- bool print_expired = true;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- // 遍歷有效鎖鏈表
- list_for_each_entry(lock, &active_wake_locks[type], link) {
- // 如果是超時鎖
- if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
- // 計算超時剩餘時間
- long timeout = lock->expires - jiffies;
- if (timeout > 0)
- pr_info("active wake lock %s, time left %ld\n",
- lock->name, timeout);
- else if (print_expired)
- pr_info("wake lock %s, expired\n", lock->name);
- } else { // 如果不是超時鎖
- pr_info("active wake lock %s\n", lock->name);
- if (!debug_mask & DEBUG_EXPIRE)
- print_expired = false;
- }
- }
- }
- static long has_wake_lock_locked(int type)
- {
- struct wake_lock *lock, *n;
- long max_timeout = 0;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- // 遍歷有效鎖鏈表
- list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
- // 如果是超時鎖
- if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
- // 計算超時剩餘時間
- long timeout = lock->expires - jiffies;
- // 如果鎖已經過期
- if (timeout <= 0)
- // 移除過期鎖
- expire_wake_lock(lock);
- else if (timeout > max_timeout) // 如果鎖沒有過期
- // 得到最長的一個超時時間
- max_timeout = timeout;
- } else // 如果不是超時鎖則返回-1
- return -1;
- }
- return max_timeout;
- }
- // 判斷系統是否還持有有效鎖
- long has_wake_lock(int type)
- {
- long ret;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- // 開始判斷流程
- ret = has_wake_lock_locked(type);
- // 如果還有休眠鎖有效則打印狀態信息
- if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
- print_active_locks(type);
- spin_unlock_irqrestore(&list_lock, irqflags);
- return ret;
- }
// 移除過期超時鎖
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;
}
has_wake_lock()爲系統判斷當前是否存在指定類型有效鎖的接口,在has_wake_lock_locked()中遍歷有效鎖鏈表,返回前面我們已經說明的值;並且打印所有有效鎖的狀態信息。6、wake_unlock
- void wake_unlock(struct wake_lock *lock)
- {
- int type;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- #ifdef CONFIG_WAKELOCK_STAT
- // 更新鎖的狀態
- wake_unlock_stat_locked(lock, 0);
- #endif
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_unlock: %s\n", lock->name);
- // 清楚有效鎖和超時鎖標誌
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- // 將鎖從有效鎖鏈表中移除加入無效鎖鏈表
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- // 如果是休眠鎖
- if (type == WAKE_LOCK_SUSPEND) {
- // 判斷系統當前是否還持有鎖
- long has_lock = has_wake_lock_locked(type);
- // 如果還持有鎖,設置timer到超時時間點觸發
- if (has_lock > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, start expire timer, "
- "%ld\n", lock->name, has_lock);
- mod_timer(&expire_timer, jiffies + has_lock);
- } else {
- if (del_timer(&expire_timer)) // 刪除timer
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- if (has_lock == 0) // 啓動深度休眠工作隊列
- queue_work(suspend_work_queue, &suspend_work);
- }
- // 如果是內核鎖
- if (lock == &main_wake_lock) {
- if (debug_mask & DEBUG_SUSPEND)
- // 打印當前有效鎖信息
- print_active_locks(WAKE_LOCK_SUSPEND);
- #ifdef CONFIG_WAKELOCK_STAT
- update_sleep_wait_stats_locked(0);
- #endif
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_unlock);
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);
該函數用於釋放一個鎖,首先將鎖從有效鎖鏈表中移除並加入無效鎖鏈表,並判斷系統是否還持有有效鎖,如果沒有則進入深度休眠流程。
7、wake_lock_active
- // 判斷鎖是否有效
- int wake_lock_active(struct wake_lock *lock)
- {
- return !!(lock->flags & WAKE_LOCK_ACTIVE);
- }
- EXPORT_SYMBOL(wake_lock_active);
// 判斷鎖是否有效
int wake_lock_active(struct wake_lock *lock)
{
return !!(lock->flags & WAKE_LOCK_ACTIVE);
}
EXPORT_SYMBOL(wake_lock_active);
8、wake_lock_destroy
- void wake_lock_destroy(struct wake_lock *lock)
- {
- unsigned long irqflags;
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock_destroy name=%s\n", lock->name);
- spin_lock_irqsave(&list_lock, irqflags);
- // 清除已經初始化的標誌
- lock->flags &= ~WAKE_LOCK_INITIALIZED;
- #ifdef CONFIG_WAKELOCK_STAT
- if (lock->stat.count) {
- deleted_wake_locks.stat.count += lock->stat.count;
- deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
- deleted_wake_locks.stat.total_time =
- ktime_add(deleted_wake_locks.stat.total_time,
- lock->stat.total_time);
- deleted_wake_locks.stat.prevent_suspend_time =
- ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
- lock->stat.prevent_suspend_time);
- deleted_wake_locks.stat.max_time =
- ktime_add(deleted_wake_locks.stat.max_time,
- lock->stat.max_time);
- }
- #endif
- // 從當前鏈表中刪除
- list_del(&lock->link);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_lock_destroy);
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);
該函數用於註銷wake_lock,首先清除 WAKE_LOCK_INITIALIZED 標誌位,然後更新統計信息,最後將鎖從鏈表中刪除。
9、proc節點
- // 獲取鎖的剩餘超時時間,通過*expire_time傳遞
- int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
- {
- struct timespec ts;
- struct timespec kt;
- struct timespec tomono;
- struct timespec delta;
- unsigned long seq;
- long timeout;
- // 如果不是超時鎖則直接返回
- if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
- return 0;
- do {
- seq = read_seqbegin(&xtime_lock);
- // 計算超時時間點與當前時間的差值
- timeout = lock->expires - jiffies;
- // 如果時間沒有到期,返回0
- if (timeout > 0)
- return 0;
- // 獲取當前時間
- kt = current_kernel_time();
- tomono = wall_to_monotonic;
- } while (read_seqretry(&xtime_lock, seq));
- // 時間格式轉換
- jiffies_to_timespec(-timeout, &delta);
- // 設置timespec的成員
- set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
- kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
- // 返回ts值
- *expire_time = timespec_to_ktime(ts);
- return 1;
- }
- // 打印出鎖的狀態信息
- static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
- {
- int lock_count = lock->stat.count;
- int expire_count = lock->stat.expire_count;
- ktime_t active_time = ktime_set(0, 0);
- ktime_t total_time = lock->stat.total_time;
- ktime_t max_time = lock->stat.max_time;
- ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
- // 如果鎖有效
- if (lock->flags & WAKE_LOCK_ACTIVE) {
- ktime_t now, add_time;
- // 獲取超時剩餘時間
- int expired = get_expired_time(lock, &now);
- if (!expired)
- now = ktime_get();
- // 計算當前時間和上次操作時間的差值
- add_time = ktime_sub(now, lock->stat.last_time);
- lock_count++; // 使用計數加1
- if (!expired) // 如果沒有到期
- active_time = add_time;
- else // 鎖已經到期
- expire_count++; // 超時計數加1
- total_time = ktime_add(total_time, add_time); // 鎖使用時間增加
- if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
- prevent_suspend_time = ktime_add(prevent_suspend_time,
- ktime_sub(now, last_sleep_time_update));
- if (add_time.tv64 > max_time.tv64)
- max_time = add_time;
- }
- return seq_printf(m,
- "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
- lock->name, lock_count, expire_count,
- lock->stat.wakeup_count, ktime_to_ns(active_time),
- ktime_to_ns(total_time),
- ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
- ktime_to_ns(lock->stat.last_time));
- }
- // 打印鎖狀態
- static int wakelock_stats_show(struct seq_file *m, void *unused)
- {
- unsigned long irqflags;
- struct wake_lock *lock;
- int ret;
- int type;
- spin_lock_irqsave(&list_lock, irqflags);
- // 輸出菜單
- ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
- "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
- // 遍歷無效鎖鏈表並打印鎖的狀態信息
- list_for_each_entry(lock, &inactive_locks, link)
- ret = print_lock_stat(m, lock);
- // 遍歷有效鎖鏈表並打印鎖的狀態信息
- for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
- list_for_each_entry(lock, &active_wake_locks[type], link)
- ret = print_lock_stat(m, lock);
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- return 0;
- }
- // proc文件打開函數,調用show函數顯示當前所有的鎖信息
- static int wakelock_stats_open(struct inode *inode, struct file *file)
- {
- return single_open(file, wakelock_stats_show, NULL);
- }
- // proc文件系統操作函數
- static const struct file_operations wakelock_stats_fops = {
- .owner = THIS_MODULE,
- .open = wakelock_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
// 獲取鎖的剩餘超時時間,通過*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,
};
以上是proc節點的操作接口,在wakelocks_init中註冊。
總結:通過以上分析我們可以看到啓動深度休眠流程有四個可能的地方,分別爲expire_timer、wake_lock、wake_lock_timeout、wake_unlock,其中expire_timer和wake_unlock最常見。