本文主要是介绍MiniGUI 定时器分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
MiniGUI 定时器分析 (注:该MiniGUI库版本为1.6.10 非LITE版本)
MiniGUI几个定时器相关的函数如下:
BOOL GUIAPI ResetTimerEx(HWND hWnd, int id, unsigned int speed, TIMERPROC timer_proc);
BOOL GUIAPI SetTimerEx(HWND hWnd, int id, unsigned int speed, TIMERPROC timer_proc);
#define SetTimer(hwnd, id, speed) SetTimerEx(hwnd, id, speed, NULL)
#define ResetTimer(hwnd, id, speed) ResetTimerEx(hwnd, id, speed, (TIMERPROC)0xFFFFFFFF)
hWnd为创建定时器时传入的窗口句柄。
id 为定时器id号
speed 为定时器时间间隔10ms 为单位。
timer_proc 为定时器回调函数
MiniGUI定时器内部运行原理
src/kernel/init.c 文件下InitGUI函数是在MiniGUI程序初始化的时候被调用的。
int GUIAPI InitGUI (int args, const char *agr[])
{
。。。
SystemThreads()
。。。
}
InitGUI函数中调用SystemThreads函数
SystemThreads函数中创建了DesktopMain线程。
pthread_create (&__mg_desktop, NULL, DesktopMain, &wait);函数
void* DesktopMain (void* data)
{
MSG Msg;
。。。
while (GetMessage(&Msg, HWND_DESKTOP)) {
int iRet = 0;
iRet = DesktopWinProc (HWND_DESKTOP, Msg.message, Msg.wParam, Msg.lParam);
。。。
}
return NULL;
}
可以看到在这里MiniGUI创建了一个桌面线程用于处理桌面线程消息。
int DesktopWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
case MSG_TIMER: // per 0.01s
{
static UINT uCounter = 0;
DispatchTimerMessage (1);
if (__mg_timer_counter % 10 != 0)
break;
uCounter += 100;
}
break;
}
在这里可以看到桌面窗口回调函数对MSG_TIMER消息的处理。调用了DispatchTimerMessage (1);函数。
timerstr该结构体数组里面最大可以放DEF_NR_TIMERS这么多个定时器,轮询每个定时器检查时间是否超时,如超时则设置定时器时间到标志,让PeekMessageEx函数做处理。
void DispatchTimerMessage (unsigned int inter)
{
int i;
TIMER_LOCK ();
for (i=0; i<DEF_NR_TIMERS; i++) {
if (timerstr[i] && timerstr[i]->msg_queue) {
timerstr[i]->count += inter;
if (timerstr[i]->count >= timerstr[i]->speed) {
if (timerstr[i]->tick_count == 0)
timerstr[i]->tick_count = __mg_timer_counter;
SetMsgQueueTimerFlag (timerstr[i]->msg_queue, i);
timerstr[i]->count -= timerstr[i]->speed;
}
}
}
TIMER_UNLOCK ();
}
SetMsgQueueTimerFlag 函数中调用了POST_MSGQ (pMsgQueue);
static inline void
SetMsgQueueTimerFlag (PMSGQUEUE pMsgQueue, int slot)
{
pMsgQueue->TimerMask |= (0x01 << slot);
POST_MSGQ (pMsgQueue); //该宏的作用是将窗口消息循环由阻塞状态唤醒。
}
此时创建该定时器的窗口过程中的消息循环PeekMessageEx会被唤醒。
BOOL PeekMessageEx (PMSG pMsg, HWND hWnd, int iMsgFilterMin, int iMsgFilterMax,
BOOL bWait, UINT uRemoveMsg)
{
。。。
if ((timer = __mg_get_timer (slot))) {
unsigned int tick_count = timer->tick_count;
timer->tick_count = 0;
pMsgQueue->TimerMask &= ~(0x01 << slot);
if (timer->proc) { //如果该定时器定义回调函数
BOOL ret_timer_proc;
UNLOCK_MSGQ (pMsgQueue);
ret_timer_proc = timer->proc (timer->hWnd, timer->id, tick_count);
LOCK_MSGQ (pMsgQueue);
if (!ret_timer_proc) {
__mg_remove_timer (timer, slot);
}
}
else {
//如果该函数回调函数指针为空则转成消息放入消息队列等着DispatchMessage函数处理
pMsg->message = MSG_TIMER;
pMsg->hwnd = timer->hWnd;
pMsg->wParam = timer->id;
pMsg->lParam = tick_count;
SET_PADD (NULL);
UNLOCK_MSGQ (pMsgQueue);
return TRUE;
}
}
。。。
}
SystemThreads函数中调用__mg_timer_init函数,该函数又启动了 TimerEntry 线程。
int __mg_timer_init (void)
{
sem_t wait;
sem_init (&wait, 0, 0);
pthread_create (&__mg_timer, NULL, TimerEntry, &wait);
sem_wait (&wait);
sem_destroy (&wait);
return 0;
}
TimerEntry 线程调用了_os_timer_loop 时间循环函数
static void* TimerEntry (void* data)
{
if (!InitTimer ()) {
fprintf (stderr, "TIMER: Init Timer failure, exit!\n");
return NULL;
}
sem_post ((sem_t*)data);
_os_timer_loop ();
return NULL;
}
时间循环函数如下
static inline void _os_timer_loop (void)
{
while (1) {
__mg_os_time_delay (10); //延时10ms
__mg_timer_action (NULL); //每10ms调用一次
}
}
每10ms AlertDesktopTimerEvent 函数被调用
static void __mg_timer_action (void *data)
{
__mg_timer_counter ++;
AlertDesktopTimerEvent ();
}
每10ms 由AlertDesktopTimerEvent 给桌面消息循环设置时间到标志,如该循环阻塞,则唤醒该循环。
AlertDesktopTimerEvent (void)
{
__mg_dsk_msg_queue->TimerMask = 1;
POST_MSGQ(__mg_dsk_msg_queue);
}
这篇关于MiniGUI 定时器分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!