MiniGUI源码分析:MiniGUIMain中有…

我们知道,一般C语言的入口都是main,那么MiniGUIMain函数怎么成为入口呢?

在MiniGUI源码include/minigui.h中,定义了宏

[cpp] view plain copy
  1. #define MiniGUIMain \  
  2. MiniGUIAppMain (int args, const char* argv[]); \  
  3. int main_entry (int args, const char* argv[]) \  
  4. { \  
  5.     int iRet = 0; \  
  6.     if (InitGUI (args, argv) != 0) { \  
  7.         return 1; \  
  8.     } \  
  9.     iRet = MiniGUIAppMain (args, argv); \  
  10.     TerminateGUI (iRet); \  
  11.     return iRet; \  
  12. } \  
  13. int MiniGUIAppMain  

其中main_entry,在linux 直接被定义为main, 但是,当_USE_MINIGUIENTRY被定义后,它被定义为minigui_entry:
[cpp] view plain copy
  1. #ifdef _USE_MINIGUIENTRY  
  2.   #define main_entry minigui_entry  
  3.   int minigui_entry (int args, const char* arg[]);  
  4. #else  
  5.   #define main_entry main  
  6. #endif  

定义minigui_entry可以用在一些RTOS系统上,如vxworks上。因为它们的入口不是从main开始的。


上面我们的程序,就被展开。可以看到,其中最最要的是InitGUI和TerminateGUI两个函数。


InitGUI函数时主要的初始化函数,我们详细分析下该函数。

InitGUI就定义在minigui.h中,它的原型是:

[cpp] view plain copy
  1. MG_EXPORT int GUIAPI InitGUI (intconst char **);  

InitGUI的实现,有多个版本,在线程版中,是在src/kernal/init.c中实现的。我们重点考察这一部分:(删除了一些不重要的部分)
[cpp] view plain copy
  1. int GUIAPI InitGUI (int args, const char *agr[])  
  2. {  
  3.     int step = 0;  
  4. .......  
  5.      if (!mg_InitFixStr ()) { //初始化字符串管理内存。MiniGUI在内部实现一个字符串的内存管理器,可以加快分配速度,减少内存碎片  
  6.         fprintf (stderr, "KERNEL>InitGUI: Init Fixed String module failure!\n");  
  7.         return step;  
  8.     }  
  9.       
  10.     step++;  
  11.       
  12.     if (!mg_InitMisc ()) { //初始化杂项,主要是加载MiniGUI.cfg文件,后面的很多操作,都依赖于MiniGUI.cfg中的配置  
  13.         fprintf (stderr, "KERNEL>InitGUI: Initialization of misc things failure!\n");  
  14.         return step;  
  15.     }  
  16.   
  17.     step++;  
  18.     switch (mg_InitGAL ()) { //初始化 GAL,它负责打开图形设备  
  19.     case ERR_CONFIG_FILE:  
  20.         fprintf (stderr,   
  21.             "KERNEL>InitGUI: Reading configuration failure!\n");  
  22.         return step;  
  23.   
  24.     case ERR_NO_ENGINE:  
  25.         fprintf (stderr,   
  26.             "KERNEL>InitGUI: No graphics engine defined!\n");  
  27.         return step;  
  28.   
  29.     case ERR_NO_MATCH:  
  30.         fprintf (stderr,   
  31.             "KERNEL>InitGUI: Can not get graphics engine information!\n");  
  32.         return step;  
  33.   
  34.     case ERR_GFX_ENGINE:  
  35.         fprintf (stderr,   
  36.             "KERNEL>InitGUI: Can not initialize graphics engine!\n");  
  37.         return step;  
  38.     }  
  39.   
  40. 。。。。。  
  41.   
  42.       
  43.     step++;  
  44.     if (!mg_InitSystemRes ()) { //初始化内建资源管理器  
  45.         fprintf (stderr, "KERNEL>InitGUI: Can not initialize system resource!\n");  
  46.         goto failure1;  
  47.     }  
  48.   
  49.       
  50.     step++;  
  51.     if(!mg_InitGDI()) { //初始化GDI, 主要是字体的初始化  
  52.         fprintf (stderr, "KERNEL>InitGUI: Initialization of GDI failure!\n");  
  53.         goto failure1;  
  54.     }  
  55.   
  56.       
  57.     step++;  
  58.     if (!mg_InitScreenDC (__gal_screen)) {//创建和初始化主屏幕  
  59.         fprintf (stderr, "KERNEL>InitGUI: Can not initialize screen DC!\n");  
  60.         goto failure1;  
  61.     }  
  62.   
  63.     g_rcScr.left = 0;  
  64.     g_rcScr.top = 0;  
  65.     g_rcScr.right = GetGDCapability (HDC_SCREEN_SYS, GDCAP_MAXX) + 1;  
  66.     g_rcScr.bottom = GetGDCapability (HDC_SCREEN_SYS, GDCAP_MAXY) + 1;  
  67.   
  68.       
  69.     step++;  
  70.     if( !mg_InitCursor() ) {//初始化光标  
  71.         fprintf (stderr, "KERNEL>InitGUI: Count not init mouse cursor!\n");  
  72.         goto failure1;  
  73.     }  
  74.   
  75.       
  76.     step++;  
  77.     if(!mg_InitLWEvent()) {//初始化IAL  
  78.         fprintf(stderr, "KERNEL>InitGUI: Low level event initialization failure!\n");  
  79.         goto failure1;  
  80.     }  
  81.   
  82.       
  83.     step++;  
  84.     if (!mg_InitLFManager ()) {//初始化Look And Feel Render管理器。这一部分是3.0独有的。  
  85.         fprintf (stderr, "KERNEL>InitGUI: Initialization of LF Manager failure!\n");  
  86.         goto failure;  
  87.     }  
  88.   
  89. #ifdef _MGHAVE_MENU  
  90.       
  91.     step++;  
  92.     if (!mg_InitMenu ()) {//初始化菜单系统  
  93.         fprintf (stderr, "KERNEL>InitGUI: Init Menu module failure!\n");  
  94.         goto failure;  
  95.     }  
  96. #endif  
  97.   
  98.       
  99.     step++;  
  100.     if(!mg_InitControlClass()) {//初始化控件类,这样可以使得预定义的控件都可以使用  
  101.         fprintf(stderr, "KERNEL>InitGUI: Init Control Class failure!\n");  
  102.         goto failure;  
  103.     }  
  104.   
  105.   
  106.  。。。。  
  107.   
  108.     step++;  
  109.     if (!mg_InitDesktop ()) { //创建和初始化一个桌面窗口。桌面窗口是非常重要的托管窗口,它是所有主窗口的父窗口,完成众多的消息分发和主窗口管理工作。它在一个单独线程中运行  
  110.         fprintf (stderr, "KERNEL>InitGUI: Init Desktop failure!\n");  
  111.         goto failure;  
  112.     }  
  113.      
  114.       
  115.     step++;  
  116.     if(!mg_InitAccel()) {  
  117.         fprintf(stderr, "KERNEL>InitGUI: Init Accelerator failure!\n");  
  118.         goto failure;  
  119.     }  
  120.   
  121.   
  122.     step++;  
  123.     if (!mg_InitDesktop ()) {  
  124.         fprintf (stderr, "KERNEL>InitGUI: Init Desktop failure!\n");  
  125.         goto failure;  
  126.     }  
  127.      
  128.     step++;  
  129.     if (!mg_InitFreeQMSGList ()) {  
  130.         fprintf (stderr, "KERNEL>InitGUI: Init free QMSG list failure!\n");  
  131.         goto failure;  
  132.     }  
  133.   
  134.   
  135.     step++;  
  136.     if (!createThreadInfoKey ()) {  
  137.         fprintf (stderr, "KERNEL>InitGUI: Init thread hash table failure!\n");  
  138.         goto failure;  
  139.     }  
  140.   
  141.   
  142.     step++;  
  143.     if (!SystemThreads()) { //创建desktop线程  
  144.         fprintf (stderr, "KERNEL>InitGUI: Init system threads failure!\n");  
  145.         goto failure;  
  146.     }  
  147.   
  148.   
  149.     SetKeyboardLayout ("default");  
  150.   
  151.   
  152.     SetCursor (GetSystemCursor (IDC_ARROW));  
  153.   
  154.   
  155.     SetCursorPos (g_rcScr.right >> 1, g_rcScr.bottom >> 1);  
  156.   
  157. #ifdef _MG_EVALUATION  
  158.     mg_InitEvaluation ();  
  159. #endif  
  160.     return 0;  
  161.   
  162. failure:  
  163.     mg_TerminateLWEvent ();  
  164. failure1:  
  165.     mg_TerminateGAL ();  
  166.     fprintf (stderr, "KERNEL>InitGUI: Init failure, please check your MiniGUI configuration or resource.\n");  
  167.     return step;  
  168. }  

TerminateGUI是一个相反的过程。有兴趣的朋友可以自己研究下,这里不再详细说明。


在线程版,当InitGUI被启动后,实际上又额外创建了3个线程,分别是Desktop线程,timer主线程和IAL线程。这是可以通过gdb 来观察。使用gdb ./helloworld,在主线程调用完InitGUI函数后暂停,通过 info threads命令,我们可以看到:

[plain] view plain copy
  1. (gdb) info threads  
  2.   4 Thread 0xb6eafb70 (LWP 23218)  0x0012d422 in __kernel_vsyscall ()  
  3.   3 Thread 0xb76b0b70 (LWP 23217)  0x0012d422 in __kernel_vsyscall ()  
  4.   2 Thread 0xb7eb1b70 (LWP 23216)  0x0012d422 in __kernel_vsyscall ()  
  5. * 1 Thread 0xb7fec6c0 (LWP 23212)  MiniGUIAppMain (argc=1, argv=0xbffff434)  
  6.     at helloworld.c:171  
其中,线程1就是主线程,另外几个线程都是由InitGUI创建的。可以通过thread N 和bt命令,得到堆栈情况:
[plain] view plain copy
  1. (gdb) thread 2  
  2. [Switching to thread 2 (Thread 0xb7eb1b70 (LWP 23216))]#0  0x0012d422 in __kernel_vsyscall ()  
  3. (gdb) bt  
  4. #0  0x0012d422 in __kernel_vsyscall ()  
  5. #1  0x0013a2e0 in sem_wait@GLIBC_2.0 () from /lib/tls/i686/cmov/libpthread.so.0  
  6. #2  0x001e67f1 in PeekMessageEx (pMsg=0xb7eb1368, hWnd=3133696, iMsgFilterMin=0,   
  7.     iMsgFilterMax=0, bWait=1, uRemoveMsg=1) at message.c:672  
  8. #3  0x001e3f9e in GetMessage (data=0xbffff32c) at ../../include/window.h:2250  
  9. #4  DesktopMain (data=0xbffff32c) at desktop-ths.c:123  
  10. #5  0x0013396e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0  
  11. #6  0x003f5a4e in clone () from /lib/tls/i686/cmov/libc.so.6  
  12. (gdb) thread 3  
  13. [Switching to thread 3 (Thread 0xb76b0b70 (LWP 23217))]#0  0x0012d422 in __kernel_vsyscall ()  
  14. (gdb) bt  
  15. #0  0x0012d422 in __kernel_vsyscall ()  
  16. #1  0x003ee971 in select () from /lib/tls/i686/cmov/libc.so.6  
  17. #2  0x00170f90 in __mg_os_time_delay (ms=10) at nposix.c:384  
  18. #3  0x001db484 in _os_timer_loop (data=0xbffff25c) at timer.c:101  
  19. #4  TimerEntry (data=0xbffff25c) at timer.c:117  
  20. #5  0x0013396e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0  
  21. #6  0x003f5a4e in clone () from /lib/tls/i686/cmov/libc.so.6  
  22. (gdb) thread 4  
  23. [Switching to thread 4 (Thread 0xb6eafb70 (LWP 23218))]#0  0x0012d422 in __kernel_vsyscall ()  
  24. (gdb) bt  
  25. #0  0x0012d422 in __kernel_vsyscall ()  
  26. #1  0x0013a4e7 in sem_post@GLIBC_2.0 () from /lib/tls/i686/cmov/libpthread.so.0  
  27. #2  0x001db8b0 in EventLoop (data=0xbffff32c) at init.c:141  
  28. #3  0x0013396e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0  
  29. #4  0x003f5a4e in clone () from /lib/tls/i686/cmov/libc.so.6  
  30. (gdb)   

线程2,其入口是DesktopMain。该函数是在src/kernel/desktop-ths.c(线程版)文件中定义的。这个函数是在InitGUI中调用SystemThreads中创建的线程并启动其运行的。


线程3,其入口是TimerEntry,该函数时MiniGUI中定时器的实现。在线程版中,它通过线程和sleep等方法获得等距时间。它的实现 在src/kernel/timer.c中。它的创建是在SystemThreads中调用__mg_timer_init函数中创建的。

线程4,其入口是EventLoop,该函数时IAL的主要监视线程。也是在SystemThreads中创建的。


连同主线程在内的这4个线程,实际上大部时间都处于休眠状态,仅仅会在有事件发生时才唤醒。所以,对CPU的影响很小。


有一些开发板在移植后,会出席CPU占用过高的情况,其中一种原因是由于IAL的实现不合理造成的。EventLoop线程依靠IAL的具体实现, 由它来阻塞线程,直到收到按键或者鼠标消息。有些开发板需要通过定时器去轮询,而不是通过select方法来等待。当轮询时间过短时,会造成cpu占用率 升高。

你可能感兴趣的:(c/c++,的代码,知识)