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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章