Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15530878
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: 嵌入式

2009-07-09 12:45:47

浅析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) |
给主人留下些什么吧!~~

chinaunix网友2009-11-02 18:19:53

兄弟真涉猎广泛啊