libminigui-1.6.8 配置为线程版
minigui定时器的创建、销毁及定时器消息MSG_TIMER的传递
1 、时钟初始化
在minigui的初始化期间,调用函数__mg_timer_init()对时钟进行初始化。
src/kernel/timer.c line 136-162
- static void* TimerEntry (void* data)
- {
- if (!InitTimer ()) {
- fprintf (stderr, "TIMER: Init Timer failure!/n");
- #ifndef __NOUNIX__
- exit (1);
- #endif
- return NULL;
- }
- sem_post ((sem_t*)data);
- __mg_os_timer_loop ();
- return NULL;
- }
- 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;
- }
函数__mg_timer_init()主要负责创建一个线程,来执行函数TimerEntry( )。在TimerEntry()函数中会通过InitTimer调用函数InstallIntervalTimer( )初始化系统时钟。
src/kernel/timer.c line 184-210
- BOOL InstallIntervalTimer (void)
- {
- struct itimerval timerv;
- struct sigaction siga;
- sigaction (SIGALRM, NULL, &old_alarm_handler);
- siga = old_alarm_handler;
- siga.sa_handler = (void(*)(int))__mg_timer_action;
- siga.sa_flags = SA_RESTART;
- sigaction (SIGALRM, &siga, NULL);
- timerv.it_interval.tv_sec = 0;
- #if defined(__uClinux__) && defined(_STAND_ALONE)
- timerv.it_interval.tv_usec = 100000; // 100 ms
- #else
- timerv.it_interval.tv_usec = 10000; // 10 ms
- #endif
- timerv.it_value = timerv.it_interval;
- if (setitimer (ITIMER_REAL, &timerv, &old_timer) == -1) {
- TIMER_LOG_SYS ("setitimer call failed!/n");
- return FALSE;
- }
- return TRUE;
- }
2 、创建定时器
minigui定时器的创建由函数SetTimer (HWND hWnd, int id, unsigned int speed)完成,这个函数主要初始化一个TIMER数据结构,然后向桌面线程发送添加时钟的消息并传递这个定时器数据结构。
src/include/timer.h line 28-34
- typedef struct _timer {
- HWND hWnd;
- int id;
- unsigned int speed;
- unsigned int count;
- }TIMER;
- typedef TIMER* PTIMER;
src/kernel/timer.c line 537-546
- BOOL GUIAPI SetTimer (HWND hWnd, int id, unsigned int speed)
- {
- TIMER timer;
- timer.hWnd = hWnd;
- timer.id = id;
- timer.speed = speed;
- return SendMessage (HWND_DESKTOP, MSG_ADDTIMER, 0, (LPARAM)&timer);
- }
src/kernel/desktop.c line 144-197
- void* DesktopMain(void* data)
- {
- MSG Msg;
- /* init message queue of desktop thread */
- if ( !(__mg_dsk_threadinfo = InitThreadInfo()) ) {
- fprintf (stderr, "DESKTOP: Init Thread Info error!/n");
- return NULL;
- }
- __mg_dsk_msgs = __mg_dsk_threadinfo->pMsgQueue;
- __mg_desktop = __mg_dsk_threadinfo->th;
- /* init desktop window */
- if (!initDesktopWindow()) return NULL;
- __mg_dsk_threadinfo->pMainWin = __mg_dsk_win;
- DesktopWinProc (HWND_DESKTOP, MSG_STARTSESSION, 0, 0);
- PostMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, 0);
- /* desktop thread is ready now */
- sem_post ((sem_t*)data);
- /* process messages of desktop thread */
- while (GetMessage(&Msg, HWND_DESKTOP)) {
- int iRet = 0;
- #ifdef _TRACE_MSG
- fprintf (stderr, "Message, %s: hWnd: %#x, wP: %#x, lP: %#lx. %s/n",
- Message2Str (Msg.message),
- Msg.hwnd,
- Msg.wParam,
- Msg.lParam,
- Msg.pAdd?"Sync":"Normal");
- #endif
- iRet = DesktopWinProc(HWND_DESKTOP, Msg.message, Msg.wParam, Msg.lParam);
- if (Msg.pAdd) // this is a sync message.
- {
- PSYNCMSG pSyncMsg = (PSYNCMSG)(Msg.pAdd);
- pSyncMsg->retval = iRet;
- sem_post(&pSyncMsg->sem_handle);
- }
- #ifdef _TRACE_MSG
- fprintf (stderr, "Message, %s done, return value: %#x/n",
- Message2Str (Msg.message), iRet);
- #endif
- }
- freeDesktopWindow ();
- FreeThreadInfo (__mg_dsk_threadinfo);
- return NULL;
- }
src/kernel/desktop-comm.c line 3104-3117
- case MSG_ADDTIMER:
- #ifdef _LITE_VERSION
- #ifdef _STAND_ALONE
- if (sg_old_counter == 0)
- sg_old_counter = __mg_timer_counter;
- #else
- if (sg_old_counter == 0)
- sg_old_counter = SHAREDRES_TIMER_COUNTER;
- #endif
- #endif
- return AddTimer (((PTIMER)lParam)->hWnd,
- ((PTIMER)lParam)->id,
- ((PTIMER)lParam)->speed);
- break;
src/kernel/timer.c line 311-386
- BOOL AddTimer (HWND hWnd, int id, unsigned int speed)
- {
- #if 0
- sigset_t sa_mask;
- #endif
- int i;
- PMAINWIN pWin;
- PMSGQUEUE pMsgQueue;
- int slot;
- if (!(pWin = GetMainWindowPtrOfControl (hWnd))) return FALSE;
- #if 0
- // block SIGALRM temporarily
- sigemptyset (&sa_mask);
- sigaddset (&sa_mask, SIGALRM);
- pthread_sigmask (SIG_BLOCK, &sa_mask, NULL);
- #endif
- pMsgQueue = pWin->pMessages;
- // Is there a empty timer slot?
- for (slot=0; slot<DEF_NR_TIMERS; slot++) {
- if ((pMsgQueue->TimerMask >> slot) & 0x01)
- break;
- }
- if (slot == DEF_NR_TIMERS) goto badret;
- for (i=0; i<MAX_TIMERS; i++)
- if (timerstr[i] != NULL)
- if (timerstr[i]->hWnd == hWnd && timerstr[i]->id == id)
- goto badret;
- for (i=0; i<MAX_TIMERS; i++)
- if (timerstr[i] == NULL)
- break;
- if (i == MAX_TIMERS)
- goto badret ;
- timerstr[i] = malloc (sizeof (TIMER));
- #if _TIMER_UNIT_10MS
- timerstr[i]->speed = speed;
- #else
- timerstr[i]->speed = (1000<<7)/speed;
- #endif
- timerstr[i]->hWnd = hWnd;
- timerstr[i]->id = id;
- timerstr[i]->count = 0;
- pMsgQueue->TimerOwner[slot] = hWnd;
- pMsgQueue->TimerID[slot] = id;
- pMsgQueue->TimerMask &= ~(0x01 << slot);
- #if 0
- // unblock SIGALRM
- pthread_sigmask (SIG_UNBLOCK, &sa_mask, NULL);
- #endif
- #if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
- if (!mgIsServer)
- set_select_timeout (USEC_10MS * speed);
- #endif
- return TRUE;
- badret:
- #if 0
- // unblock SIGALRM
- pthread_sigmask (SIG_UNBLOCK, &sa_mask, NULL);
- #endif
- return FALSE;
- }
3 、定时器消息的传递
前面在时钟初始化的最后提到,SIGALRM信号的处理函数是__mg_timer_action。现在看看这个函数都做了哪些事情
src/kernel/timer.c line 75-93
- static void __mg_timer_action (void *data)
- {
- #if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
- SHAREDRES_TIMER_COUNTER += 1;
- #else
- #if defined(__uClinux__) && defined(_STAND_ALONE)
- __mg_timer_counter += 10;
- #else
- __mg_timer_counter ++;
- #endif
- #endif
- #ifndef _LITE_VERSION
- // alert desktop
- AlertDesktopTimerEvent ();
- #endif
- }
首先将__mg_timer_counter加1,然后调用AlertDesktopTimerEvent()通知桌面线程过去了一个时钟间隔,
src/kernel/message.c line 195-199
- void AlertDesktopTimerEvent (void)
- {
- __mg_dsk_msgs->dwState |= 0x01;
- POST_MSGQ(__mg_dsk_msgs);
- }
注意这里通过 __mg_dsk_msgs->dwState |= 0x01; 标识消息队列中有了一个定时器消息。在桌面线程的消息循环中会检测这个标记
src/kernel/message.c line 571-586
- if (pMsgQueue->dwState & QS_TIMER && IS_MSG_WANTED(MSG_TIMER)) {
- #ifndef _LITE_VERSION
- if (hWnd == HWND_DESKTOP) {
- pMsg->hwnd = hWnd;
- pMsg->message = MSG_TIMER;
- pMsg->wParam = 0;
- pMsg->lParam = 0;
- SET_PADD (NULL);
- if (uRemoveMsg == PM_REMOVE) {
- pMsgQueue->dwState &= ~0x01;
- }
- UNLOCK_MSGQ (pMsgQueue);
- return 1;
- }
- #endif
- ……
可以看到,这段代码的开头就对状态标志进行检测,QS_TIMR这window.h中定义
include/window.h line 1667
- #define QS_TIMER 0x0000FFFF
这样就可以检测到AlertDesktopTimerEvent函数中设置的标志位。然后将这个消息放到一个消息数据结构中,发送给相应的消息处理函数。桌面线程的消息处理函数是DesktopWinProc,在desktop-comm.c文件中定义
src/kernel/desktop.c line 3243-3248
- DispatchTimerMessage (1);
- if (__mg_timer_counter % 10 != 0)
- break;
- uCounter += 100;
这段代码就是处理MSG_TIMER消息的,它调用了函数DispatchTimerMessage(),
src/kernel/timer.c line 273-309
- void DispatchTimerMessage (unsigned int inter)
- {
- PMAINWIN pWin;
- PMSGQUEUE pMsgQueue;
- int i, slot;
- for ( i=0; i<MAX_TIMERS; i++ ) {
- if ( timerstr[i] ) {
- #if _TIMER_UNIT_10MS
- timerstr[i]->count += inter;
- #else
- timerstr[i]->count += 1<<7;
- #endif
- if ( timerstr[i]->count >= timerstr[i]->speed ) {
- pWin = GetMainWindowPtrOfControl (timerstr[i]->hWnd);
- if (pWin == NULL) continue;
- pMsgQueue = pWin->pMessages;
- LOCK_MSGQ (pMsgQueue);
- /* optimization: save slot in timerstr[i] */
- for (slot=0; slot<DEF_NR_TIMERS; slot++) {
- if (pMsgQueue->TimerID[slot] == timerstr[i]->id
- && pMsgQueue->TimerOwner[slot] == timerstr[i]->hWnd)
- break;
- }
- if (slot != DEF_NR_TIMERS) {
- SetMsgQueueTimerFlag (pMsgQueue, slot);
- }
- UNLOCK_MSGQ (pMsgQueue);
- timerstr[i]->count -= timerstr[i]->speed;
- }
- }
- }
- }
在创建定时器(SetTimer (HWND hWnd, int id, unsigned int speed))时,传递的参数speed就是这个定时的长度有多少个时钟时间间隔,每个时间间隔是10ms。这个在初始化时钟时设置好的。在上的函数中先将时钟间隔计数的值加上传递进来的时间间隔数(line 282).然后与对应的speed进行比较,如果达到或超过这个间隔数就在对应的窗口消息队列标记中添加标记(line 301).
在创建定时器(SetTimer (HWND hWnd, int id, unsigned int speed))时,传递的参数hWnd就是想要获得定时器消息的那个窗口,在把定时器消息放到这个窗口的消息队列后,就可以由它的消息循环获得定时器消息MSG_TIMER了。注意,MSG_TIMER对应的wParam是定时器的id。如果同时有几个定时器发送MSG_TIMER消息,通过这个id可判断来自哪个定时器,以便做出相应处理。