xserver源碼分析之解析xorg.conf

一、X系統基本概念:
XServer 是一個集中信息處理系統,它負責從 XClient 進程接收繪圖指令(原始數據),並將本地的輸入設備產生的數據轉換爲消息發送到 XClient 進程。這個過程看似簡單,但實際上流程比較複雜,極端情況下,當 XServer 獲得輸入設備產生的數據後,它先要發送給窗口管理器(窗口管理器很可能還在另一臺主機上,需要通過網絡傳輸),再接收窗口管理器發出的請求,再將輸入數據發送到真正的 XClient(又有可能通過網絡),XClient 處理完消息後向 XServer 發送繪圖請求(又有可能是網絡),再由 XServer 執行繪圖渲染工作,這其中如果使用到的字體不在本地,還要通過訪問字體服務器(又有可能是網絡)獲取字體數據後再行渲染。而花哨到極點的 compize 之類的聚合窗口管理器因爲需要在多個XClient產生的窗口上進行復合渲染,造成XClient遞交的繪圖指令被多次重複運行,更是讓XServer在效率上雪上加霜。

GTK—–>windowmanager—>xserver—>驅動適配層庫——>kernel

二、體系結構:
xserver目錄下包含多個X服務器的源碼,包括Xorg, Xnest和基於kdrive的多個服務器。
X服務器的代碼分爲四個部分組織:
設備無關層(DIX), 這一部分的代碼被所有Xserver的實現共享。
操作系統層(OS), 這一部分的代碼隨着操作系統的不同而不同,但是被這個操作系統上的圖形設備共享。
設備相關層(DDX), 這一部分隨着操作系統和圖形設備的組合的不同而不同。
擴展接口,這一部分爲用統一的方式向X server加入新的功能提供支持。
服務器相關部分的代碼放置在hw/目錄下。其中,hw/xfree86/目錄下包含了Xorg的代碼; hw/kdrive下 保 括 了 基 於kdrive的 多 個 服 務 器

三、main函數進入一個大循環,這個循環的第一步是完成初始化工作,第二部是進入Dispatch() 事
件處理循環,第三步是釋放所有的資源。這個大循環的退出即意味着main函數的退出。下面我們
一步步的分析初始化過程。
本人用的xserver版本是xserver_xorg-server-1.15.1,
跟蹤源碼從main函數開始吧,
路徑在 dix/main.c

131 int main(int argc, char *argv[], char *envp[])
132 #endif
133 {
134     int         i;
135     HWEventQueueType    alwaysCheckForInput[2];
136 
137     display = "0";
138 
139     InitRegions();
140 
141     pixman_disable_out_of_bounds_workaround();
142 
143     CheckUserParameters(argc, argv, envp);
144 
145     CheckUserAuthorization();
146 
147     InitConnectionLimits();
148 
149     ProcessCommandLine(argc, argv);

main函數前面主要是一些初始化工作

while1)
{
    ........
205 InitOutput(&screenInfo, argc, argv);
    ..........
}

接下來進入到了一個while循環,咱們找的解析xorg.xonf文件在initoutput裏做的,跟進去路徑在hw/xfree86/common/xf86Init.c

...............
 361     /* Read and parse the config file */
 362     if (!xf86DoConfigure && !xf86DoShowOptions) {
 363       switch (xf86HandleConfigFile(FALSE)) {
 364       case CONFIG_OK:
 365         break;
..........

繼續看xf86HandleConfigFile(FALSE)函數實現
路徑hw/xfree86/common/xf86Config.c +2383

2379         xf86initConfigFiles();
2380         sysdirname =    xf86openConfigDirFiles(SYS_CONFIGDIRPATH, NULL,
2381                                                      PROJECTROOT);
2382         dirname = xf86openConfigDirFiles(dirsearch, xf86ConfigDir, PROJECTROOT);
2383         filename = xf86openConfigFile(filesearch, xf86ConfigFile, PROJECTROOT); 

跟進函數xf86openConfigFile()

 906 #ifndef DEFAULT_CONF_PATH
 907 #define DEFAULT_CONF_PATH       "/etc/X11/%S," \                                                         "%P/etc/X11/%S," \                                                         "/etc/X11/%G," \                                                       "%P/etc/X11/%G," \                                                       "/etc/X11/%X-%M," \                                                       "/etc/X11/%X," \                                                   "/etc/%X," \                                                        "%P/etc/X11/%X.%H," \                                                        "%P/etc/X11/%X-%M," \                                                      "%P/etc/X11/%X," \                                                     "%P/lib/X11/%X.%H," \                                                       "%P/lib/X11/%X-%M," \                                                       "%P/lib/X11/%X"
 920 #endif
 921             
 922 const char *
 923 xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)                                                         
 924 {
 925         if (!path || !path[0])
 926                 path = DEFAULT_CONF_PATH;
 927         if (!projroot || !projroot[0])
 928                 projroot = PROJECTROOT;
 929 
 930         /* Search for a config file */
 931         configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
 932         return configPath; 
 933 }

在這可以看到xorg.conf默認在/etc的一些路徑下,看configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);的實現
路徑在hw/xfree86/parser/scan.c

730  * Given some searching parameters, locate and open the xorg config file.                                                               
 731  */
 732 static char *
 733 OpenConfigFile(const char *path, const char *cmdline, const char *projroot,
 734                const char *confname)
 735 {
 736         char *filepath = NULL;
 737         char *pathcopy;
 738         const char *template;
 739         int cmdlineUsed = 0;
 740         FILE *file = NULL;
 741         
 742         pathcopy = strdup(path);
 743         for (template = strtok(pathcopy, ","); template && !file;
 744              template = strtok(NULL, ",")) {
 745                 filepath = DoSubstitution(template, cmdline, projroot,
 746                                           &cmdlineUsed, NULL, confname);
 747                 if (!filepath)
 748                         continue;
 749                 if (cmdline && !cmdlineUsed) {
 750                         free(filepath);
 751                         filepath = NULL;
 752                         continue;
 753                 }
 754                 file = fopen(filepath, "r");
 755                 if (!file) {
 756                         free(filepath);
 757                         filepath = NULL;
 758                 }

到此結束,這個流程都是在判斷xorg文件是否存在。

四、接下來看代碼分析如何解析xorg.conf文件的
路徑在hw/xfree86/common/xf86Init.c

 393     if (xf86DoConfigure)
 394         DoConfigure();

跟進 DoConfigure()在hw/xfree86/common/xf86Configure.c

635     if (xf86writeConfigFile(filename, xf86config) == 0) {
636         xf86Msg(X_ERROR, "Unable to write config file: \"%s\": %s\n",                                                                    
637                 filename, strerror(errno));
638         goto bail;
639     }

跟進xf86writeConfigFile()路徑在hw/xfree86/parser/write.c

212 return doWriteConfigFile(filename, cptr);                                      

繼續跟

114         xf86printVendorSection (cf, cptr->conf_vendor_lst);
115 
116         xf86printServerFlagsSection (cf, cptr->conf_flags);
117 
118         xf86printInputSection (cf, cptr->conf_input_lst);
119 
120         xf86printInputClassSection (cf, cptr->conf_inputclass_lst);
121 
122         xf86printVideoAdaptorSection (cf, cptr->conf_videoadaptor_lst);
123 
124         xf86printModesSection (cf, cptr->conf_modes_lst);
125 
126         xf86printMonitorSection (cf, cptr->conf_monitor_lst);
127 
128         xf86printDeviceSection (cf, cptr->conf_device_lst);
129 
130         xf86printScreenSection (cf, cptr->conf_screen_lst);
131 
132         xf86printDRISection (cf, cptr->conf_dri);
133 
134         xf86printExtensionsSection (cf, cptr->conf_extensions);

到這裏我們可以看到不同功能的解析函數
進入xf86printInputSection()

140         while (ptr)
141         {
142                 fprintf (cf, "Section \"InputDevice\"\n");
143                 if (ptr->inp_comment)
144                         fprintf (cf, "%s", ptr->inp_comment);
145                 if (ptr->inp_identifier)
146                         fprintf (cf, "\tIdentifier  \"%s\"\n", ptr->inp_identifier);
147                 if (ptr->inp_driver)
148                         fprintf (cf, "\tDriver      \"%s\"\n", ptr->inp_driver);
149                 xf86printOptionList(cf, ptr->inp_option_lst, 1);
150                 fprintf (cf, "EndSection\n\n");
151                 ptr = ptr->list.next;
152         }

在這我們終於明白爲什麼xorg.conf文件爲什麼按
Section \”InputDevice
Identifier
Driver
EndSection 格式寫了

五、如何找到驅動適配層庫
代碼路徑hw/xfree86/common/xf86Init.c

 407     /* Load all modules specified explicitly in the config file */
 408     if ((modulelist = xf86ModulelistFromConfig(&optionlist))) {
 409       xf86LoadModules(modulelist, optionlist);
 410       free(modulelist);
 411       free(optionlist);
 412     }

跟進 xf86LoadModules(modulelist, optionlist);函數

1430         if (!LoadModule(name, NULL, NULL, NULL, opt, NULL, &errmaj, &errmin)) {
1431             LoaderErrorMsg(NULL, name, errmaj, errmin);
1432             failed = TRUE;

跟進函數LoadModule()路徑在hw/xfree86/loader/loadmod.c

1058   return doLoadModule(module, path, subdirlist, patternlist, options,modreq, errmaj, errmin);

繼續跟 doLoadModule()

 892      * if the module name is not a full pathname, we need to
 893      * check the elements in the path
 894      */
 895     if (PathIsAbsolute(module))
 896         found = xstrdup(module);
 897     path_elem = pathlist;
 898     while (!found && *path_elem != NULL) {
 899         found = FindModule(m, *path_elem, subdirlist, patterns);
 900         path_elem++;
 901         /*

跟進FindModule()函數

 452     for (s = subdirs; *s; s++) {
 453         if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX)
 454             continue;
 455         strcpy(buf, dirpath);
 456         strcat(buf, *s);
 457         if ((name = FindModuleInSubdir(buf, module)))                                                                                   
 458             break;

跟進 FindModuleInSubdir()

398         /* the stat with the appended / fails for normal files,
 399            and works for sub dirs fine, looks a bit strange in strace                                                                   
 400            but does seem to work */
 401         if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) {
 402             if ((ret = FindModuleInSubdir(tmpBuf, module)))
 403                 break;
 404             continue;
 405         }
 406  
 407         snprintf(tmpBuf, PATH_MAX, "lib%s.so", module);
 408         if (strcmp(direntry->d_name, tmpBuf) == 0) {
 409             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
 410                 ret = NULL;
 411             break;
 412         }
 413 
 414         snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module);
 415         if (strcmp(direntry->d_name, tmpBuf) == 0) {
 416             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
 417                 ret = NULL;
 418             break;
 419         }
 420 
 421         snprintf(tmpBuf, PATH_MAX, "%s.so", module);
 422         if (strcmp(direntry->d_name, tmpBuf) == 0) {
 423             if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1)
 424                 ret = NULL;
 425             break;

到這裏結束,會發現xserver在啓動時,會根據xorg.xonf去load相應的驅動適配層庫,庫的名字是組合的例如觸屏的庫叫tslib_drv.so

發佈了35 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章