2) 库和接口函数
对于更上一层的应用程序而言,当其注册了自己的模块进入电源管理中之后,会调用一些接口来进行设置,那么我们该设置那些接口给应用层调用呢?(该部分在client中实现)
i) 获取定时器A的超时时间
ii) 设置定时器A的超时时间(注意锁)
iii) 设置是否允许进入电源管理,是否开启定时器B(由state文件锁的占有情况决定,见server思考)
iv) 实现应用程序状态通知到server的方法,由状态的变化决定state文件
v) 注册应用程序(链表),设置状态,如果状态为不允许进入休眠则调用库进行设置对应文件的操作(一般就电源NODE和下载的NODE)
以上提到的接口就是提供给应用的一些思路,而对应中间的库函数则是client端和接口
之间的一层细化操作,也应该得到注意。
3) 应用的状态切换
根据应用程序的工作状态(根据文件锁决定)决定定时器B的开关涉及到一个状态机的设计。
如果必要的情况下,会维护一个线程装用于检测状态,这个在电源供电框架中提到。所以可以封装一个接口函数,进行两部分初始化
1、对省电模式处理部分进行初始化,注册电源管理节点
2、如果是电池供电,则启动电源状态维护线程,以便即时更新状态信息,进行一些必要的操作。
Server为每个应用程序维护一个电源管理状态有三种状态,如图:
五.电源供电框架(kernel)与电源管理 (app)
事实上,我们还遗漏了一个问题,对于使用电源供电和电池供电的电源管理分析。在前面提到过,client会为维护一个线程,用于处理应用与server之间的工作,同时提供库和接口。而电源状态的变化这个过程除了人为的设置之外,还受所使用的电源的影响。
电源状态的监控是用uevent事件实现的。Linux内核中,供电部分的框架(drivers/power目录下,power_supply_core,power_supply_sysfs)提供了uevent机制,驱动可以在电源状态发生变化时发送uevent事件到用户空间,从而通知系统做相应的处理。(对于内核空间与用户空间的uevent通信,用的始终是NETLINK_KOBJECT_UEVENT这个socket通道)。
目前在下面这些情况下产生UEVENT事件:
(1)电池电量等级变化:电池电量等级包括满、高电量、普通电量、低电量、电量不足
(2)外电插入、拔出
(3)充电状态改变:包括充电中、禁止充电、不在充电、充饱等状态
所以,我们启动给一个电源状态维护线程,监控UEVENT事件发生,同时对不同的uevent事件调用不同的电源管理接口。比如在外电插入的情况下禁止进入休眠,在电池低电量的时候允许进入休眠等设置。
六.一些细节
1. 以前提到过系统调用的用法,在电源管理中定时器也用到了系统调用,下载timerfd.patch,实现部分如下,
#if defined(__arm__)
#define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
#define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
#define TFD_TIMER_ABSTIME (1 << 0)
#endif
//#endif /* __NR_timerfd_create */
static int timerfd_create(int clockid, int flags)
{
return syscall(__NR_timerfd_create, clockid, flags);
}
static int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr, struct itimerspec *otmr)
{
return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr);
}
2. __attribute__ ((constructor))
Gcc为函数提供了几种类型的属性,其中有构造函数constructor和析构函数destructors
Static void start(void) __attribute__ ((constructor))
Static void stop(void) __attribute__ ((destructors))
带有构造函数属性的函数会在main函数之前执行,而析构函数会在_after_main()退出时执行,具体的问题分析可以参见
http://chongsoft.bokee.com/5738209.html
转载博客
__attribute__ ((__format__(__printf__,m,n)))
This指针,继承概念
3. 在client中涉及到threadWakeup_fd,因为它是创建的一个事件fd,用于socket更新时,通知系统重新poll,所以比较简单
调用threadWakeup_fd=eventfd(0);
Fcntl(threadWakeup_fd,F_SETFD,FD_CLOEXEC);
当需要通知系统重新poll时,只要向该fd中写入一些数据,原来的poll会有事件上报,在该处理函数中,通知重新poll。
4. 关于用户空间定时器的一些操作
内核空间的定时器的使用在linux内核一些机制中提到过。
这里说的用户空间的定时器的操作,到最终的操作肯定为内核定时器。
Timer_fd=timerfd_create(CLOCK_MONOTONIC,0); //
Timerfd_settime(timer_fd,0,&tmr,NULL) //启动定时器
定时时间在struct itimerspec tmr结构中,这个定时器不像内核定时器,可以在时间到时调用定时处理函数,所以我们需要将此fd加入select或者poll中,从而在时间超时时做相应的处理。
5. static int close_socket(int fd)
{
Shutdown(fd,SHUT_RDWR);
Return close(fd);
}
读取一个文件有多少数据可读
Ioctl(fd,FIONREAD,&ibytestoread);
---END---