目录
Linux wakeup source实现
1 模块功能介绍
在Linux kernel中,wakeup source是睡眠流程中各个组件关于本业务是否同意睡眠的一套投票机制。整套机制框架基本上是围绕着combined_event_count这个变量在处理逻辑,在此变量中,高16位记录系统处理过的所有的wakeup event总数,低16位记录在处理中的wakeup events总数。在每次持锁时,处理中的wakeup events会加1(低16位);每次释放锁时,处理中的wakeup events会减1(低16位),同步已处理的wakeup event会加1(高16位)。对于每次系统是否能够进入睡眠,通过判定是否有正在处理中的wakeup events来判断。实现的主要功能有:
1)持锁功能
2)释放锁功能
3)注册锁功能
4)去注册锁功能
5)查询激活状态锁个数功能
2 功能属性
特性功能受宏CONFIG_PM_SLEEP控制,需要打开该特性的话,CONFIG_PM_SLEEP必须设置为y。
相关实现在drivers\base\power\wakeup.c文件中,相关函数声明在include\linux\pm_wakeup.h中
3 主要结构体/变量介绍
3.1 struct wakeup_source
1)结构体原型:
struct wakeup_source {
const char *name;
int id;
struct list_head entry;
spinlock_t lock;
struct wake_irq *wakeirq;
struct timer_list timer;
unsigned long timer_expires;
ktime_t total_time;
ktime_t max_time;
ktime_t last_time;
ktime_t start_prevent_time;
ktime_t prevent_sleep_time;
unsigned long event_count;
unsigned long active_count;
unsigned long relax_count;
unsigned long expire_count;
unsigned long wakeup_count;
struct device *dev;
bool active:1;
bool autosleep_enabled:1;
};
2)成员变量说明:
name:顾名思义,即该wakesource的名字,方便记录查看
id:wakesource模块给本wakesource分配的ID
entry:链表结构,用于把本wakesource节点维护到系统wakesource的全局链表中
lock:保护本结构体变量访问所使用的互斥锁
wakeirq:与本wakesource绑定的唤醒中断相关结构体,用户可以把指定中断与wakesource做绑定
timer:超时使用,比如定义本wakesource为超时锁,即过一段指定的时间后把锁释放,可以使用本变量来设置
timer_expires:要设置的定时器的超时时间
total_time:记录本wakesource激活的总时长
max_time:在wakesource激活的历史中,最长一次的激活时间
last_time:最近一次访问本wakesource的时间
prevent_sleep_time:因为本wakesource的原因导致的阻止autosleep进入睡眠的总时间
event_count:如果是本wakesource被持锁,则event_count就会加1作为维测记录
active_count:注意持锁接口是可在上次没有释放锁时再次调用的,每次调用持锁接口event_count会加1,但是active_count只会在第一次active时加1
relax_count:每次释放锁时,该值会累加1,与active_count一一对应
expire_count:对应的超时锁超时的次数
wakeup_count:由于竞态的存在,这个值只是一个大概值,仅供参考,伴随event一起增加,比较鸡肋
dev:与wakesource绑定的dev设备
active:标记是否处于active激活状态
autosleep_enabled:标记autosleep是否使能
3.2 combined_event_count
static atomic_t combined_event_count = ATOMIC_INIT(0);
该变量是个组合计数变量,高16位记录wakeup event的总计数,低16位记录正在处理中的wakeup event。系统根据正在处理中的wakeup event来判断是否可以进入睡眠。
3.3 wakeup_sources
static LIST_HEAD(wakeup_sources);
所有注册的wakeup source全部维护在该链表中,便于系统进行wakesource的维护工作。
4 主要函数介绍
本节主要介绍下wakeup.c中的关键函数,因为很多内部使用的函数本身也比较简单,所以也不用再做过多介绍,感兴趣的可以参考源码实现。
在wakeup.c中,对外接口通常是成对出现的,比如
1)wakeup_source_register和wakeup_source_unregister,分别对应注册和去注册一个wakesource。
2)pm_stay_awake与pm_relax,针对device类型的对象提供的持锁和释放锁接口。
3)__pm_stay_awake和__pm_relax,则是针对wakeup_source类型的对象提供的持锁和释放锁接口。
其中2)和3)两组接口,在对应场景中配套使用即可。
4.1 wakeup_source_register
1)函数说明
函数原型 |
|