对技术执着
分类: LINUX
2015-03-14 15:28:50
当手机满足一定的条件时,会进入休眠状态。从手机进入休眠到唤醒,主要分为三个阶段:
early suspend
suspend
late resume
early suspend执行在休眠前需要完成的一些工作,late resume完成在退出休眠后进行的一些扫尾工作。early suspend与late resume执行的操作是一一对应的。
early_suspend的结构
需要early suspend和late resume执行的操作,通过函数register_early_suspend注册,unregister_early_suspend取消注册。
early_suspend的结构体如下:
struct early_suspend {
struct list_head link;
int level; //节点的级别,控制执行顺序
void (*suspend)(struct early_suspend *h); //early_suspend执行的函数
void (*resume)(struct early_suspend *h); //late_resume执行的函数
};
register_early_suspend(struct early_suspend *handler)
{
struct list_head *pos;
list_for_each(pos, &early_suspend_handlers) {
struct early_suspend *e;
e = list_entry(pos, struct early_suspend, link);
if (e->level > handler->level)
break;
}
list_add_tail(&handler->link, pos);
if ((state & SUSPENDED) && handler->suspend)
handler->suspend(handler);
}
注册early_suspend变量,就是在链表early_suspend_handlers中增加该节点,level小的节点排前面。所有early_suspend注册结束后,early_suspend_handlers就是按照节点的level从小到大排列的链表。
early suspend的执行
在文件系统中有一个虚拟的文件:/sys/power/state
向该文件写入字符串“mem”,则启动进入休眠的过程。
向该文件写入字符串“on”,则手机退出休眠状态。
其中Const char* const pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_ON]="on",
...................
[PM_SUSPEND_MEM] = "mem",
};
向state文件写入字符串,对应函数的操作如下:
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
suspend_state_t state = PM_SUSPEND_ON;//初始化值为“on”=0
const char * const *s;
char *p;
int len;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;//取出输入字符串的长度
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;//找到对应的输入状态
}
if (state < PM_SUSPEND_MAX && *s)
if (state == PM_SUSPEND_ON || valid_state(state)) {//如果状态为“on”或者“mem”
request_suspend_state(state);//调用该函数
}
}
——————————————————————————————————————————————————————————————————————————————
/*回调函数的注册与实现*/
static struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
};
static int __init msm_pm_init(void)
suspend_set_ops(&msm_pm_ops);
suspend_ops = ops;
其中static const struct platform_suspend_ops *suspend_ops;是本文件的全局变量
bool valid_state(suspend_state_t state)
{
//调用上面注册valid函数
return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
}
上面注册的valid函数如下:
int suspend_valid_only_mem(suspend_state_t state)
{
return state == PM_SUSPEND_MEM;
}
这些枚举变量定义如下:
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1)
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
还有一个函数是 msm_pm_enter
static int msm_pm_enter(suspend_state_t state)
{
................................
rs_limits = msm_rpmrs_lowest_limits(false,
MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1, -1);
...........................
if (rs_limits) {
ret = msm_rpmrs_enter_sleep(msm_pm_max_sleep_time, rs_limits, false, true);
if (!ret) {
int collapsed = msm_pm_power_collapse(false);//进入休眠,等待中断
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
collapsed = msm_pm_l2x0_power_collapse();
msm_pm_collapse();
ENTRY(msm_pm_collapse)//idle-v7.S(arch\arm\mach-msm)
....................
Wfi//休眠在此
............
msm_rpmrs_exit_sleep(rs_limits, false, true, collapsed);//退出休眠
}
}
enter_exit:
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: return\n", __func__);
return 0;
}
其中wfi指令定义如下:
#define wfi() __asm__ __volatile__ ("wfi" : : : "memory")
WFI(Wait For Interrupt)指令,讓ARM等待外部中斷例如:IRQ或FIQ,對產品端而言就是手機的按鍵或是透過Real-Time Clock的中斷,喚醒處理器,恢復正常的執行.
WFI 会暂时将执行中断挂起,直至发生以下事件后再恢复执行:
发生 IRQ 中断,不考虑 CPSR I 位
发生 FIQ 中断,不考虑 CPSR F 位
发生不精确的数据中止,除非被 CPSR A 位屏蔽
出现调试进入请求,无论是否启用调试
——————————————————————————————————————————————————————————————————————————————
接着上面的函数讲 request_suspend_state()
enum {
SUSPEND_REQUESTED = 0x1,
SUSPENDED = 0x2,
SUSPEND_REQUESTED_AND_SUSPENDED=SUSPEND_REQUESTED| SUSPENDED,
};
static int state;// state全局变量
void request_suspend_state(suspend_state_t new_state)
{
unsigned long irqflags;
int old_sleep;
old_sleep = state & SUSPEND_REQUESTED; //保存旧的suspend状态
//如果旧的状态不为SUSPEND_REQUESTED,并且新请求的状态为“mem”
if (!old_sleep && new_state != PM_SUSPEND_ON) {
state |= SUSPEND_REQUESTED;//把state的状态置为SUSPEND_REQUESTED
queue_work(suspend_work_queue, &early_suspend_work);//进入early suspend的处理
} else if (old_sleep && new_state == PM_SUSPEND_ON) {
//如果旧的状态为SUSPEND_REQUESTED,并且新请求的状态为“on”
state &= ~SUSPEND_REQUESTED;//清除SUSPEND_REQUESTED标记
wake_lock(&main_wake_lock);//锁定main_wake_lock,进入late resume处理流程
queue_work(suspend_work_queue, &late_resume_work);
}
requested_suspend_state = new_state;//保存请求的状态
}
下面看下early_suspend_work,late_resume_work的注册处理Wakelock.c (kernel\power)
static DEFINE_SPINLOCK(list_lock);
static LIST_HEAD(inactive_locks);
static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
struct workqueue_struct *suspend_work_queue;
struct wake_lock main_wake_lock;
suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
static int __init wakelocks_init(void)
{
for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
INIT_LIST_HEAD(&active_wake_locks[i]);
wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
wake_lock(&main_wake_lock);
..................
suspend_work_queue = create_singlethread_workqueue("suspend");
}
下面看下两个work的声明
static DECLARE_WORK(early_suspend_work, early_suspend);
static DECLARE_WORK(late_resume_work, late_resume);
处理函数如下
static void early_suspend(struct work_struct *work)
{
struct early_suspend *pos;
if (state == SUSPEND_REQUESTED)
state |= SUSPENDED;//如果为request,则继续置位suspend
else
abort = 1;
if (abort) {
goto abort;
}
suspend_sys_sync_queue();
abort:
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)//如果状态为3
wake_unlock(&main_wake_lock);//解锁main_wake_lock
}
下面是该函数的实现:suspend_sys_sync_queue
static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);
void suspend_sys_sync_queue(void)
{
ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);
if (ret)
suspend_sys_sync_count++;//该work还没执行完
}
static void suspend_sys_sync(struct work_struct *work)
{
pr_info("PM: Syncing filesystems...\n");
sys_sync();//具体做同步文件系统的操作
pr_info("sync done.\n");
suspend_sys_sync_count--;//执行完毕,减一
}
static void late_resume(struct work_struct *work)
{
if (state == SUSPENDED)
state &= ~SUSPENDED;//把全局变量状态state取反
pr_info("late_resume: done\n");
}
下面进入wakelock的操作:
一个线程运行时,如果要防止手机进入休眠,则需要定义一个wake_lock,并且锁定该wake_lock。当允许睡眠时,解锁该wake_lock。以alarm设置的wake_lock (kernel\drivers\rtc\ alarm.c)为例:
定义:
static struct wake_lock alarm_rtc_wake_lock;
初始化
wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
阻止手机进入睡眠时,锁定该wake_lock:
wake_lock(&alarm_rtc_wake_lock);
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
允许手机进入睡眠时,解除锁定:
wake_unlock(&alarm_rtc_wake_lock);
wake_lock结构体的定义如下:(用于统计的字段没有列出)
struct wake_lock {
struct list_head link; //加入链表时用
int flags; //wake_lock的标志
const char *name; //名称
unsigned long expires; //超时记录
};
其中,flags各个bit的定义如下:
#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)
wake_lock的类型定义如下:
enum {
WAKE_LOCK_SUSPEND, /* Prevent suspend */
WAKE_LOCK_IDLE, /* Prevent low power idle */
WAKE_LOCK_TYPE_COUNT
};
void wake_lock_init(struct wake_lock *lock, int type, const char *name)
{
lock->name = name;
lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
INIT_LIST_HEAD(&lock->link);
list_add(&lock->link, &inactive_locks);
}
初始化时,把该wake_lock放入不活动的链表inactive_locks。
static LIST_HEAD(inactive_locks);
以下时刻会把一个wake_lock放入inactive_locks链表:
初始化 wake_lock_init
解锁 wake_lock
定时锁定超时 expire_wake_lock
以下两个函数执行锁定wake_lock的操作:
void wake_lock(struct wake_lock *lock)
{
wake_lock_internal(lock, 0, 0);
}
void wake_lock_timeout(struct wake_lock *lock, long timeout)
{
wake_lock_internal(lock, timeout, 1);
}
wake_lock是硬锁定,只有通过wake_unlock才能解锁。
wake_lock_timeout则只锁定一段时间,超时后,自动解除锁定。
两个函数都调用wake_lock_internal。
wake_lock_internal的主要操作:
static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)
{
type = lock->flags & WAKE_LOCK_TYPE_MASK; // WAKE_LOCK_SUSPEND = 0
lock->flags |= WAKE_LOCK_ACTIVE;
list_del(&lock->link); //从inactive_locks链表中删除
if (has_timeout) {
lock->expires = jiffies + timeout;
lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
list_add_tail(&lock->link, &active_wake_locks[type]);
}
else {
lock->expires = LONG_MAX;
lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
list_add(&lock->link, &active_wake_locks[type]);
}
if (type == WAKE_LOCK_SUSPEND) { //如果类型为WAKE_LOCK_SUSPEND
current_event_num++;
if (has_timeout)
expire_in = has_wake_lock_locked(type);//检查活动的wake_locks链表
else
expire_in = -1;
if (expire_in > 0) {
mod_timer(&expire_timer, jiffies + expire_in);//超时时间没到期
} else {
del_timer(&expire_timer)//没有超时
if (expire_in == 0)//没有锁定的wakelock,则suspend_work压入工作队列
queue_work(suspend_work_queue, &suspend_work);
}
}
锁定wake_lock时,把该wake_lock从inactive_locks链表中删除,然后加入active_wake_locks[type]链表,其定义如下:
static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
enum {
WAKE_LOCK_SUSPEND, /* Prevent suspend */
WAKE_LOCK_IDLE, /* Prevent low power idle */
WAKE_LOCK_TYPE_COUNT
};
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;
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);//检查活动的wake_locks链表
if (has_lock > 0) {
mod_timer(&expire_timer, jiffies + has_lock);
} else {
del_timer(&expire_timer)
if (has_lock == 0)
queue_work(suspend_work_queue, &suspend_work);
}
}
}
解锁一个wake_lock时,先设置其flag,然后把该wake_lock从活动的wake_locks链表中删除,加入非活动的wake_locks链表中。
上面两个函数同时都调到has_wake_lock_locked函数,来检查活动的wake_locks链表
static long has_wake_lock_locked(int type) {
long max_timeout = 0;
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
return -1;
}
return max_timeout;
}
has_wake_lock_locked返回三类数值:
大于0,活动的wake_lock中没有硬锁定的wake_lock,有定时锁定的wake_lock,返回值为最大的超时时间与当前时间的差。这时会启动定时器expire_timer,该定时器超时后执行函数expire_wake_locks,这时会再次检查是否有活动的wake_lock,如果没有了,则把suspend_work压入工作队列。
等于0,活动的wake_lock中没有硬锁定的wake_lock,定时锁定的wake_lock都已超时,解除了锁定(expire_wake_lock)。此时已没有任何锁定的wake_lock,可以执行休眠的操作了,把suspend_work压入工作队列。
小于0,-1,活动的wake_lock中有硬锁定的wake_lock。此时只能等待调用wake_unlock解除对应wake_lock的锁定。
static DECLARE_WORK(suspend_work, suspend);//所有的wakelock都解锁后,执行该函数
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0); //超时后,执行该函数
static void expire_wake_locks(unsigned long data)
{
long has_lock;
has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);//检查有没有锁定?
if (has_lock == 0)
queue_work(suspend_work_queue, &suspend_work);
}
无论通过哪种途径,只要最后检测到没有锁定的wake_lock,则把suspend对应的work放入工作队列suspend_work_queue。
工作队列suspend_work_queue专门处理休眠唤醒相关的操作,在文件Wakelock.c (kernel\power)中定义:
struct workqueue_struct *suspend_work_queue;
在函数wakelocks_init中初始化:
suspend_work_queue = create_singlethread_workqueue("suspend");
static void suspend(struct work_struct *work)
{
suspend_sys_sync_queue();//同步文件系统
pr_info("suspend: enter suspend\n");
ret = pm_suspend(requested_suspend_state);
}
跟踪调用关系:
int pm_suspend(suspend_state_t state)
enter_state(state);
suspend_sys_sync_queue(); //同步文件系统
suspend_prepare();//(1)
suspend_devices_and_enter(state);//(2)
suspend_finish();//(3)与suspend_prepare函数的后半部分对比,完全相同。
挂起用户空间进程
——————————————————————————————————————
(1)suspend_prepare();
static int suspend_prepare(void)
{
pm_prepare_console();
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
if (error)
goto Finish;
error = usermodehelper_disable();
if (error)
goto Finish;
error = suspend_freeze_processes();// 让各个进程进入休眠,可能某些进程不能进入休眠, // 则返回失败
if (!error)//如果顺利,正常进入休眠,从这里返回,否则,唤醒进程
return 0;
suspend_thaw_processes();// 后半部分恢复的操作,与suspend_finish的操作相同
usermodehelper_enable();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
return error;
}
其中suspend_freeze_processes();
int freeze_processes(void)//从串口打出来的log就是从该函数输出
{
printk("Freezing user space processes ... ");
error = try_to_freeze_tasks(true);
printk("done.\n");
error = suspend_sys_sync_wait();
printk("Freezing remaining freezable tasks ... ");
error = try_to_freeze_tasks(false);
printk("done.");
}
其中suspend_thaw_processes();
void thaw_processes(void)
{
printk("Restarting tasks ... ");
................
printk("done.\n");
}
——————————————————————————————————
设备的挂起,唤醒过程
——————————————————————————————————
(2) suspend_devices_and_enter()
int suspend_devices_and_enter(suspend_state_t state)
{
...............
suspend_console(); // 禁止控制台打印,此后,串口没有打印输出,此时会输出log: //"Suspending console(s) (use no_console_suspend to debug)
..........
error = dpm_suspend_start(PMSG_SUSPEND);(2-1)
.....................
error = suspend_enter(state);(2-2)//休眠于此
Resume_devices:
dpm_resume_end(PMSG_RESUME);(2-3)
resume_console();
}
(2-1)dpm_suspend_start()//进入休眠
int dpm_suspend_start(pm_message_t state)
{
dpm_prepare(state);// 逐个执行每个device注册的prepare函数
dpm_suspend(state);// 逐个执行每个device注册的suspend函数
}
(2-2)suspend_enter(state);
suspend_ops->enter(state);//该函数已在前面分析过(msm_pm_enter),设备休眠在此
//唤醒后,继续向下执行
(2-3)dpm_resume_end()//退出休眠
void dpm_resume_end(pm_message_t state)
{
dpm_resume(state);// 逐个执行每个device的resume函数
dpm_complete(state);// 逐个执行每个device的complete函数
}