Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1594925
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4427
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: LINUX

2012-08-19 23:25:56

当手机满足一定的条件时,会进入休眠状态。从手机进入休眠到唤醒,主要分为三个阶段:

 

early suspend

suspend

late resume

 

early suspend执行在休眠前需要完成的一些工作,late resume完成在退出休眠后进行的一些扫尾工作。early suspendlate resume执行的操作是一一对应的。

 

early_suspend的结构

需要early suspendlate 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等待外部中斷例如:IRQFIQ,對產品端而言就是手機的按鍵或是透過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_worklate_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_lockinactive_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函数的后半部分对比,完全相同。

挂起用户空间进程

——————————————————————————————————————

1suspend_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-1dpm_suspend_start()//进入休眠

int dpm_suspend_start(pm_message_t state)

{

dpm_prepare(state);// 逐个执行每个device注册的prepare函数

dpm_suspend(state);// 逐个执行每个device注册的suspend函数

}

2-2suspend_enter(state);

suspend_ops->enter(state);//该函数已在前面分析过(msm_pm_enter),设备休眠在此

                             //唤醒后,继续向下执行

2-3dpm_resume_end()//退出休眠

void dpm_resume_end(pm_message_t state)

{

dpm_resume(state);// 逐个执行每个deviceresume函数

dpm_complete(state);// 逐个执行每个devicecomplete函数

}

阅读(7286) | 评论(0) | 转发(5) |
给主人留下些什么吧!~~