浅析minigui的3个重要系统线程DesktopMain﹑TimerEntry和EventLoop
1.创建3个系统线程
InitGUI==>SystemThreads创建minigui运行所需的3个必需线程.
static BOOL SystemThreads(void)
{
sem_t wait;
sem_init (&wait, 0, 0); // 信号初始化
// this is the thread for desktop window.
// this thread should have a normal priority same as
// other main window threads.
// if there is no main window can receive the low level events,
// this desktop window is the only one can receive the events.
// to close a MiniGUI application, we should close the desktop
// window.
#ifdef __NOUNIX__
{
pthread_attr_t new_attr;
pthread_attr_init (&new_attr);
pthread_attr_setstacksize (&new_attr, 16 * 1024);
pthread_create (&__mg_desktop, &new_attr, DesktopMain, &wait);
pthread_attr_destroy (&new_attr);
}
#else
pthread_create (&__mg_desktop, NULL, DesktopMain, &wait); //创建第1个线程DesktopMain桌面消息
#endif
sem_wait (&wait); // 等待DesktopMain线程运行,DesktopMain线程起来之后,会发送sem_post[luther.gliethttp].
__mg_timer_init (); // 创建第2个线程TimerEntry定时器
// this thread collect low level event from outside,
// if there is no event, this thread will suspend to wait a event.
// the events maybe mouse event, keyboard event, or timeout event.
//
// this thread also parse low level event and translate it to message,
// then post the message to the approriate message queue.
// this thread should also have a higher priority.
pthread_create (&__mg_parsor, NULL, EventLoop, &wait);// 创建第3个线程EventLoop鼠标键盘处理
sem_wait (&wait); // 等待EventLoop线程运行,EventLoop线程起来之后,会发送sem_post[luther.gliethttp].
sem_destroy (&wait);
return TRUE;
}
int __mg_timer_init (void)
{
sem_t wait;
sem_init (&wait, 0, 0);
pthread_create (&__mg_timer, NULL, TimerEntry, &wait);
sem_wait (&wait); // 等待TimerEntry线程运行,TimerEntry线程起来之后,会发送sem_post[luther.gliethttp].
sem_destroy (&wait);
return 0;
}
2.三个系统线程的线程处理函数的具体实现
2.1先来看看DesktopMain桌面消息处理线程DesktopMain
void* DesktopMain (void* data)
{
MSG Msg;
/* init message queue of desktop thread */
if (!(__mg_dsk_msg_queue = InitMsgQueueThisThread ()) ) { // 创建消息队列
fprintf (stderr, "DESKTOP: InitMsgQueueThisThread failure!\n");
return NULL;
}
/* init desktop window */
init_desktop_win(); // 源码见后
__mg_dsk_win->th = pthread_self (); // 记住Desktop所在线程id
__mg_dsk_msg_queue->pRootMainWin = __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);// 通知SystemThreads()函数调用所在主线程,"我起来了!"[luther.gliethttp]
/* process messages of desktop thread */
while (GetMessage(&Msg, HWND_DESKTOP)) { // 从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. */
{
// 这是一个sync同步消息,需要发送回执
PSYNCMSG pSyncMsg = (PSYNCMSG)(Msg.pAdd);
pSyncMsg->retval = iRet;
sem_post(pSyncMsg->sem_handle);
// 向正在处于sem_wait(pSyncMsg->sem_handle)期间的消息发起者(该发起者因为调用SendMessage,
// 发现向其他thread[即Desktop线程发送消息]而被阻塞),发送sem_post信号[luther.gliethttp]
}
#ifdef _TRACE_MSG
fprintf (stderr, "Message, %s done, return value: %#x\n",
Message2Str (Msg.message), iRet);
#endif
}
return NULL;
}
#define HWND_DESKTOP __mg_hwnd_deskto
HWND_DESKTOP指向了__mg_hwnd_deskto全局量
static void init_desktop_win (void)
{
static MAINWIN sg_desktop_win; // 静态量
PMAINWIN pDesktopWin;
pDesktopWin = &sg_desktop_win; // 作为默认的Desktop
pDesktopWin->pMessages = __mg_dsk_msg_queue; // 自己的消息队列,其他窗口发送的SendMessage将消息压入该队列[luther.gliethttp]
pDesktopWin->MainWindowProc = DesktopWinProc; // 桌面默认回调处理函数
pDesktopWin->DataType = TYPE_HWND;
pDesktopWin->WinType = TYPE_ROOTWIN;
pDesktopWin->pLogFont = NULL;
pDesktopWin->spCaption = "THE DESKTOP WINDOW";
pDesktopWin->pGCRInfo = &sg_ScrGCRInfo;
pDesktopWin->pMainWin = pDesktopWin;
__mg_hwnd_desktop = (HWND)pDesktopWin; // 登记到desktop的全局量中
// window.h
// #define HWND_DESKTOP __mg_hwnd_desktop
__mg_dsk_win = pDesktopWin;
}
2.2再来看看TimerEntry定时器线程
static void* TimerEntry (void* data)
{
if (!InitTimer ()) { // 创建一个互斥索,源码见后
fprintf (stderr, "TIMER: Init Timer failure, exit!\n");
#ifndef __NOUNIX__
exit (1);
#endif
return NULL;
}
sem_post ((sem_t*)data); // 通知SystemThreads()函数调用所在主线程,"我起来了!"[luther.gliethttp]
_os_timer_loop (); // 进入定时器loop,源码见后
return NULL;
}
BOOL InitTimer (void)
{
#ifdef _LITE_VERSION
InstallIntervalTimer ();
#endif
#ifndef _LITE_VERSION
pthread_mutex_init (&timerLock, NULL); // 创建一个互斥锁
__mg_timer_counter = 0; // 延时次数
#endif
return TRUE;
}
static inline void _os_timer_loop (void)
{
while (1) {
__mg_os_time_delay (10); // 调用系统延时函数,延时10ms,如果minigui运行在linux系统,那么就是usleep (ms * 1000);
__mg_timer_action (NULL);
}
}
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 ++; // 10ms个数
#endif
#endif
#ifndef _LITE_VERSION
/* alert desktop */
AlertDesktopTimerEvent (); // 通知给Desktop,使用了__mg_dsk_msg_queue->TimerMask方式通知DesktopMain线程
// 因为10ms就会产生一个数据,所以不会将timer信息以消息队列方式发布出去,这样太浪费.[luther.gliethttp]
#endif
}
2.3最后谈谈EventLoop鼠标键盘数据获取线程
static void* EventLoop (void* data)
{
LWEVENT lwe;
int event;
lwe.data.me.x = 0; lwe.data.me.y = 0;
sem_post ((sem_t*)data);// 通知SystemThreads()函数调用所在主线程,"我起来了!"[luther.gliethttp]
while (TRUE) {
// ial.h
// #define IAL_WaitEvent (*__mg_cur_input->wait_event) // 调用wait_event()函数
event = IAL_WaitEvent (IAL_MOUSEEVENT | IAL_KEYEVENT, // 阻塞等待按键或者鼠标信息
NULL, NULL, NULL, (void*)&__mg_event_timeout);
if (event < 0)
continue;
lwe.status = 0L;
// 加工获得的信息,之后将信息QueueDeskMessage发布给Desktop的消息队列[luther.gliethttp]
if (event & IAL_MOUSEEVENT && GetLWEvent (IAL_MOUSEEVENT, &lwe))
ParseEvent (&lwe);
lwe.status = 0L;
if (event & IAL_KEYEVENT && GetLWEvent (IAL_KEYEVENT, &lwe))
ParseEvent (&lwe);
if (event == 0 && GetLWEvent (0, &lwe))
ParseEvent (&lwe);
}
return NULL;
}
阅读(4091) | 评论(1) | 转发(0) |