您的位置:首页 > 移动开发 > Android开发

android 休眠唤醒机制分析(一) — wake_lock

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

一、wake_lock 定义和接口

[cpp] view
plaincopy

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、内核空间接口

[cpp] view
plaincopy

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()用于解锁使之成为无效锁。另外还有两个接口:

[cpp] view
plaincopy

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向用户空间提供了两个文件节点用于申请锁和解锁:

[cpp] view
plaincopy

// 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的实现代码,首先看看其定义的一些初始化信息:

[cpp] view
plaincopy

#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系统初始化

[cpp] view
plaincopy

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初始化

[cpp] view
plaincopy

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()激活该锁:

[cpp] view
plaincopy

// 根据参数激活锁

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

[cpp] view
plaincopy

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

[cpp] view
plaincopy

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

[cpp] view
plaincopy

// 移除过期超时锁

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

[cpp] view
plaincopy

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

[cpp] view
plaincopy

// 判断锁是否有效

int wake_lock_active(struct wake_lock *lock)

{

return !!(lock->flags & WAKE_LOCK_ACTIVE);

}

EXPORT_SYMBOL(wake_lock_active);

8、wake_lock_destroy

[cpp] view
plaincopy

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节点

[cpp] view
plaincopy

// 获取锁的剩余超时时间,通过*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最常见。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: