linux 用户空间电源管理 (二)

三.Server

Server本身维护一个定时器,当定时器超时,就让系统进入节能模式。Server会接受其它进程的重置定时器的命令,阻止系统进入节能模式。

Server主要功能包括:

l        当定时器超时,让系统进入节能模式。

l        接受来至其它进程的连接注册(可能)。

l        接收来至其它进程的重置定时器命令。

l        接收来至其它进程的修改超时命令,维护超时时间在各个进程间同步。

l        通知其它进程系统准备进入节能模式和离开节能模式事件。

 

通过分析它的主要功能,我们可以设计如下的结构

 

  

 

 

在调用poll时,不仅包括上述的timer_fd,inotify_fd,socket_fd,reset_fd,还需要包括已注册

的所有client_fd,需要监控的evdev_fd(这里选择监控input设备中的keyboard)

       socket_fdclient_fd数组相关,inotify_fdevdev_fd数组相关。

       每当/dev/input/eventX有输入时,则重置定制器。

       在应用修改超时时间,事件需要广播(其他应用和电源管理器都需要知道此事件),使用inotify机制,应用和管理器都监听超时文件是否被修改,当发生修改之后,应用和管理器都重新读取超时文件的内容,更新超时时间。 

 

       整个server端的设计是比较简单的,就是全面的考虑电源管理所涉及的内容,然后对这些部分进行监控,如果有对应的事件就进行相应的处理,需要注意的是锁的使用和对事件的清除操作(一般通过读该文件清除)

 

   思考:

1.     如何表明server已经运行? 通过一个lock文件来实现。当lock文件被锁则

server在运行,如果lock文件未被锁,则server未运行。

2.     对于server端,我们要考虑的问题就是定时器允许超时和不允许超时的情况,比

如在某些情况下是不允许进入睡眠模式的,这个时候需要通过client事件来实现。

对于系统休眠是所有注册的client同意的情况下才进入睡眠模式的。如果一个client不同意则永远不进入休眠。

设计一个定时器B(client),区别于server的定时器A,运行定时器B和定时器A,当定时器B超时时(修改serverclient共同访问的reset文件,reset_fd),则重置定时器A,保证定时器A不超时,从而不进入休眠。这样,我们把定时器A是否超时的控制权交给了client的定时器B,而定时器B是否超时(从而决定系统是否有可能进入休眠)由应用程序的状态决定的。

如果应用程序不允许进入省电,则设置工作状态为work,这样会启动定时器B,保证不进入睡眠。如果所有关联的应用程序均允许进入睡眠,则关闭定时器B,在满足条件的情况下,可以进入休眠。

是否允许启动定时器B,可以和思考1提到的部分一致,设置state文件,当该文件被锁时,启动定时器B,不允许进入休眠,否则反之。

 

 

 

四、client

1) 设计思路

对于上面提到的思考2,有了一个更清晰的认识,client端不仅仅是client的功能,还是一个库的概念。注册的应用程序通过调用client端提供的库函数,来实现对定时器B的操作。

 

client端,维护一个线程(如果server没有运行,则这个线程也不运行)。

       线程等待如下事件:

l 定时器B超时,将重置server端的定时器A,阻止系统进入节能模式。

l Server的定时器A超时时间被改变,将更新超时时间,如果当前状态为不允许进入休眠,还需要重启client的定时器B

l 应用调用Register函数和server建立起新连接,则开始监听这个连接。

l Server通知用户,准备进入节能模式和退出节能模式,调用相应的回调函数。

分析其功能,可以设置如下的结构,

 

整个client部分与server想关的功能还是比较简单的,关键在于库的注册函数和一些与各个应用的接口。

 

思考:

在新的应用register时,我们会通过eventfd,threadwakeupfd通知socket fd更新自己的socket_fd,从而保证client线程中的socket fd是与server socket通道相bind的最新的socket fd.

这样就会存在一个问题,因为在server中,我们有fd_client数组用于记录bindserver 的所有socket,在广播resumesuspend事件时,可以通过fd_client数组逐一发送信号给远端地址,通知resumesuspend事件,而对于client端得socket_fd,只有一个,所以若发送失败则关闭对应的远端地址,从而只有最后一个注册到client中的应用的socket能收到server的信息。

也就是说最后一个socket需要通知所有的远端地址,已经收到resume或者suspend的通知,让他们调用自己的回调函数。故涉及到遍历通知信息的过程,所以设计注册函数时,需要注意链表的使用。(事实上大多的注册函数,多对一的情况下都需要考虑链表问题)

 

                                                               -- TO BE CONTINUED

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章