Xorg启动分析笔记

1、main函数位于dix/stubmain.c

cpp 复制代码
int dix_main(int argc, char *argv[], char *envp[]);

/*
  A default implementation of main, which can be overridden by the DDX
*/
int
main(int argc, char *argv[], char *envp[])
{
    return dix_main(argc, argv, envp);
}

dix_main()按"server generation"运行;这意味着收到 reset 时,Xorg 可以清理当前客户端与屏幕状态后重新初始化,而不必立即退出
2、dix_main函数
dix_main()
├─ InitOutput() 初始化显示子系统
│ ├─ 读取配置、探测设备、加载驱动
│ ├─ 驱动 PreInit() 确定能力、颜色格式、显示模式
│ └─ 驱动 ScreenInit() 建立屏幕和绘制基础设施
├─ InitExtensions() 注册 GLX、RANDR、RENDER 等扩展
├─ CreateScreenResources() 建立屏幕 pixmap 等资源
├─ InitInput() 初始化输入子系统
└─ Dispatch() 处理客户端请求与事件

cpp 复制代码
int
dix_main(int argc, char *argv[], char *envp[])
{
    int i;
    HWEventQueueType alwaysCheckForInput[2];
    display = "0";
    InitRegions();

    // 校验权限、解析参数
    CheckUserParameters(argc, argv, envp);
    CheckUserAuthorization();
    ProcessCommandLine(argc, argv);

    alwaysCheckForInput[0] = 0;
    alwaysCheckForInput[1] = 1;
    while (1) {
        serverGeneration++;
        ScreenSaverTime = defaultScreenSaverTime;
        ScreenSaverInterval = defaultScreenSaverInterval;
        ScreenSaverBlanking = defaultScreenSaverBlanking;
        ScreenSaverAllowExposures = defaultScreenSaverAllowExposures;

        InitBlockAndWakeupHandlers();
        // OS 初始化并创建 X11 监听 socket
        OsInit();
        if (serverGeneration == 1) {
            CreateWellKnownSockets();
            for (i = 1; i < LimitClients; i++)
                clients[i] = NullClient;
            serverClient = calloc(1, sizeof(ClientRec));
            if (!serverClient)
                FatalError("couldn't create server client");
            InitClient(serverClient, 0, (void *) NULL);
        }
        else
            ResetWellKnownSockets();
        clients[0] = serverClient;
        currentMaxClients = 1;

        // 初始化服务端内部 client、资源系统、Atom、事件、字体。
        /* clear any existing selections */
        InitSelections();

        /* Initialize privates before first allocation */
        dixResetPrivates();

        /* Initialize server client devPrivates, to be reallocated as
         * more client privates are registered
         */
        if (!dixAllocatePrivates(&serverClient->devPrivates, PRIVATE_CLIENT))
            FatalError("failed to create server client privates");

        if (!InitClientResources(serverClient)) /* for root resources */
            FatalError("couldn't init server resources");

        SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]);
        screenInfo.numScreens = 0;
        InitAtoms();
        InitEvents();
        xfont2_init_glyph_caching();
        dixResetRegistry();
        InitFonts();
        InitCallbackManager();

        // 显示硬件抽象为一个或多个 Screen
        InitOutput(&screenInfo, argc, argv);
        if (screenInfo.numScreens < 1)
            FatalError("no screens found");
        InitExtensions(argc, argv); // 初始化 X11 扩展
        for (i = 0; i < screenInfo.numGPUScreens; i++) {
            ScreenPtr pScreen = screenInfo.gpuscreens[i];
            if (!PixmapScreenInit(pScreen))
                FatalError("failed to create screen pixmap properties");
            if (pScreen->CreateScreenResources &&
                !(*pScreen->CreateScreenResources) (pScreen))
                FatalError("failed to create screen resources");
        }
        for (i = 0; i < screenInfo.numScreens; i++) {
            ScreenPtr pScreen = screenInfo.screens[i];
            if (!PixmapScreenInit(pScreen))
                FatalError("failed to create screen pixmap properties");
            if (pScreen->CreateScreenResources &&
                !(*pScreen->CreateScreenResources) (pScreen))
                FatalError("failed to create screen resources");
            if (!CreateGCperDepth(i))
                FatalError("failed to create scratch GCs");
            if (!CreateDefaultStipple(i))
                FatalError("failed to create default stipple");
            if (!CreateRootWindow(pScreen))
                FatalError("failed to create root window");
            CallCallbacks(&RootWindowFinalizeCallback, pScreen);
        }

        if (SetDefaultFontPath(defaultFontPath) != Success) {
            ErrorF("[dix] failed to set default font path '%s'",
                   defaultFontPath);
        }
        if (!SetDefaultFont("fixed")) {
            FatalError("could not open default font");
        }

        if (!(rootCursor = CreateRootCursor())) {
            FatalError("could not open default cursor font");
        }
        rootCursor = RefCursor(rootCursor);
#ifdef PANORAMIX
        /*
         * Consolidate window and colourmap information for each screen
         */
        if (!noPanoramiXExtension)
            PanoramiXConsolidate();
#endif
        for (i = 0; i < screenInfo.numScreens; i++)
            InitRootWindow(screenInfo.screens[i]->root);

        // 初始化核心输入设备和 DDX 输入
        InitCoreDevices();
        InitInput(argc, argv);
        InitAndStartDevices();
        ReserveClientIds(serverClient);
        dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset);
        dixCloseRegistry();

#ifdef PANORAMIX
        if (!noPanoramiXExtension) {
            if (!PanoramiXCreateConnectionBlock()) {
                FatalError("could not create connection block info");
            }
        }
        else
#endif
        {
            if (!CreateConnectionBlock()) {
                FatalError("could not create connection block info");
            }
        }

        NotifyParentProcess();
        InputThreadInit();

        // 整个服务器的核心循环
        Dispatch();

        // 退出
        UnrefCursor(rootCursor);
        UndisplayDevices();
        DisableAllDevices();

        /* Now free up whatever must be freed */
        if (screenIsSaved == SCREEN_SAVER_ON)
            dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
        FreeScreenSaverTimer();
        CloseDownExtensions();
#ifdef PANORAMIX
        {
            Bool remember_it = noPanoramiXExtension;


            noPanoramiXExtension = TRUE;
            FreeAllResources();
            noPanoramiXExtension = remember_it;
        }
#else
        FreeAllResources();
#endif

        CloseInput();
        InputThreadFini();
        for (i = 0; i < screenInfo.numScreens; i++)
            screenInfo.screens[i]->root = NullWindow;
        CloseDownDevices();
        CloseDownEvents();

        for (i = screenInfo.numGPUScreens - 1; i >= 0; i--) {
            ScreenPtr pScreen = screenInfo.gpuscreens[i];
            dixFreeScreenSpecificPrivates(pScreen);
            (*pScreen->CloseScreen) (pScreen);
            dixFreePrivates(pScreen->devPrivates, PRIVATE_SCREEN);
            free(pScreen);
            screenInfo.numGPUScreens = i;
        }

        for (i = screenInfo.numScreens - 1; i >= 0; i--) {
            FreeGCperDepth(i);
            FreeDefaultStipple(i);
            dixFreeScreenSpecificPrivates(screenInfo.screens[i]);
            (*screenInfo.screens[i]->CloseScreen) (screenInfo.screens[i]);
            dixFreePrivates(screenInfo.screens[i]->devPrivates, PRIVATE_SCREEN);
            free(screenInfo.screens[i]);
            screenInfo.numScreens = i;
        }

        ReleaseClientIds(serverClient);
        dixFreePrivates(serverClient->devPrivates, PRIVATE_CLIENT);
        serverClient->devPrivates = NULL;
        dixFreeRegistry();
        FreeFonts();
        FreeAllAtoms();
        FreeAuditTimer();
        DeleteCallbackManager();
        ClearWorkQueue();

        if (dispatchException & DE_TERMINATE) {
            CloseWellKnownConnections();
        }

        OsCleanup((dispatchException & DE_TERMINATE) != 0);
        if (dispatchException & DE_TERMINATE) {
            ddxGiveUp(EXIT_NO_ERROR);
            break;
        }

        free(ConnectionInfo);
        ConnectionInfo = NULL;
    }
    return 0;
}

3、初始化output,位于hw/xfree86/common/xf86Init.c
配置 + 设备
↓ 加载驱动
DriverRec
↓ Probe:发现可管理的设备实例
ScrnInfoRec
↓ PreInit:确定配置和能力
配置可用的 ScrnInfoRec
↓ AddScreen + ScreenInit
ScreenRec,与 ScrnInfoRec 关联

cpp 复制代码
void
InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
{
    int i, j, k, scr_index;
    const char **modulelist;
    void **optionlist;
    Bool autoconfig = FALSE;
    Bool sigio_blocked = FALSE;
    Bool want_hw_access = FALSE;
    GDevPtr configured_device;
    xf86Initialising = TRUE;

    config_pre_init();
    if (serverGeneration == 1) {
        xf86PrintBanner();
        LogPrintMarkers();
        if (xf86LogFile) {
            time_t t;
            const char *ct;
            t = time(NULL);
            ct = ctime(&t);
            xf86MsgVerb(xf86LogFileFrom, 0, "Log file: \"%s\", Time: %s", xf86LogFile, ct);
        }

        /* Read and parse the config file */
        if (!xf86DoConfigure && !xf86DoShowOptions) {
            switch (xf86HandleConfigFile(FALSE)) {
            case CONFIG_OK:
                break;
            case CONFIG_PARSE_ERROR:
                xf86Msg(X_ERROR, "Error parsing the config file\n");
                return;
            case CONFIG_NOFILE:
                autoconfig = TRUE;
                break;
            }
        }

        /* Initialise the loader */
        LoaderInit();

        /* Tell the loader the default module search path */
        LoaderSetPath(xf86ModulePath);

        if (xf86Info.ignoreABI) {
            LoaderSetOptions(LDR_OPT_ABI_MISMATCH_NONFATAL);
        }

        if (xf86DoShowOptions)
            DoShowOptions();
        dbus_core_init();
        systemd_logind_init();

        /* Do a general bus probe.  This will be a PCI probe for x86 platforms */
        xf86BusProbe();
        if (xf86DoConfigure)
            DoConfigure();

        if (autoconfig) {
            if (!xf86AutoConfig()) {
                xf86Msg(X_ERROR, "Auto configuration failed\n");
                return;
            }
        }

        xf86OSPMClose = xf86OSPMOpen();
        xf86ExtensionInit();
        /* Load all modules specified explicitly in the config file */
        if ((modulelist = xf86ModulelistFromConfig(&optionlist))) {
            xf86LoadModules(modulelist, optionlist);
            free(modulelist);
            free(optionlist);
        }

        /* Load all driver modules specified in the config file */
        /* If there aren't any specified in the config file, autoconfig them */
        /* FIXME: Does not handle multiple active screen sections, but I'm not
         * sure if we really want to handle that case*/
        configured_device = xf86ConfigLayout.screens->screen->device;
        if ((!configured_device) || (!configured_device->driver)) {
            if (!autoConfigDevice(configured_device)) {
                xf86Msg(X_ERROR, "Automatic driver configuration failed\n");
                return;
            }
        }
        if ((modulelist = xf86DriverlistFromConfig())) {
            xf86LoadModules(modulelist, NULL);
            free(modulelist);
        }

        /* Load all input driver modules specified in the config file. */
        if ((modulelist = xf86InputDriverlistFromConfig())) {
            xf86LoadModules(modulelist, NULL);
            free(modulelist);
        }

        /*
         * It is expected that xf86AddDriver()/xf86AddInputDriver will be
         * called for each driver as it is loaded.  Those functions save the
         * module pointers for drivers.
         * XXX Nothing keeps track of them for other modules.
         */
        /* XXX What do we do if not all of these could be loaded? */
        /*
         * At this point, xf86DriverList[] is all filled in with entries for
         * each of the drivers to try and xf86NumDrivers has the number of
         * drivers.  If there are none, return now.
         */
        if (xf86NumDrivers == 0) {
            xf86Msg(X_ERROR, "No drivers available.\n");
            return;
        }

        /*
         * Call each of the Identify functions and call the driverFunc to check
         * if HW access is required.  The Identify functions print out some
         * identifying information, and anything else that might be
         * needed at this early stage.
         */
        for (i = 0; i < xf86NumDrivers; i++) {
            xorgHWFlags flags = HW_IO;
            if (xf86DriverList[i]->Identify != NULL)
                xf86DriverList[i]->Identify(0);
            if (xf86DriverList[i]->driverFunc)
                xf86DriverList[i]->driverFunc(NULL, GET_REQUIRED_HW_INTERFACES, &flags);
            if (NEED_IO_ENABLED(flags))
                want_hw_access = TRUE;
            /* Non-seat0 X servers should not open console */
            if (!(flags & HW_SKIP_CONSOLE) && !ServerIsNotSeat0() && xf86HasTTYs())
                xorgHWOpenConsole = TRUE;
        }

        if (xorgHWOpenConsole)
            xf86OpenConsole();
        else
            xf86Info.dontVTSwitch = TRUE;

    /* Enable full I/O access */
    if (want_hw_access)
        xorgHWAccess = xf86EnableIO();
        if (xf86BusConfig() == FALSE)
            return;
        xf86PostProbe();

        /*
         * Sort the drivers to match the requested ordering.  Using a slow
         * bubble sort.
         */
        for (j = 0; j < xf86NumScreens - 1; j++) {
            for (i = 0; i < xf86NumScreens - j - 1; i++) {
                if (xf86Screens[i + 1]->confScreen->screennum < xf86Screens[i]->confScreen->screennum) {
                    ScrnInfoPtr tmpScrn = xf86Screens[i + 1];
                    xf86Screens[i + 1] = xf86Screens[i];
                    xf86Screens[i] = tmpScrn;
                }
            }
        }
        /* Fix up the indexes */
        for (i = 0; i < xf86NumScreens; i++) {
            xf86Screens[i]->scrnIndex = i;
        }

        /*
         * Call the driver's PreInit()'s to complete initialisation for the first
         * generation.
         */
        for (i = 0; i < xf86NumScreens; i++) {
            xf86VGAarbiterScrnInit(xf86Screens[i]);
            xf86VGAarbiterLock(xf86Screens[i]);
            if (xf86Screens[i]->PreInit && xf86Screens[i]->PreInit(xf86Screens[i], 0))
                xf86Screens[i]->configured = TRUE;
            xf86VGAarbiterUnlock(xf86Screens[i]);
        }
        for (i = 0; i < xf86NumScreens; i++)
            if (!xf86Screens[i]->configured)
                xf86DeleteScreen(xf86Screens[i--]);
        for (i = 0; i < xf86NumGPUScreens; i++) {
            xf86VGAarbiterScrnInit(xf86GPUScreens[i]);
            xf86VGAarbiterLock(xf86GPUScreens[i]);
            if (xf86GPUScreens[i]->PreInit && xf86GPUScreens[i]->PreInit(xf86GPUScreens[i], 0))
                xf86GPUScreens[i]->configured = TRUE;
            xf86VGAarbiterUnlock(xf86GPUScreens[i]);
        }
        for (i = 0; i < xf86NumGPUScreens; i++)
            if (!xf86GPUScreens[i]->configured)
                xf86DeleteScreen(xf86GPUScreens[i--]);

        /*
         * If no screens left, return now.
         */
        if (xf86NumScreens == 0) {
            xf86Msg(X_ERROR, "Screen(s) found, but none have a usable configuration.\n");
            return;
        }

        /* Remove (unload) drivers that are not required */
        for (i = 0; i < xf86NumDrivers; i++)
            if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0)
                xf86DeleteDriver(i);

        /*
         * At this stage we know how many screens there are.
         */
        for (i = 0; i < xf86NumScreens; i++)
            xf86InitViewport(xf86Screens[i]);

        /*
         * Collect all pixmap formats and check for conflicts at the display
         * level.  Should we die here?  Or just delete the offending screens?
         */
        for (i = 0; i < xf86NumScreens; i++) {
            if (xf86Screens[i]->imageByteOrder !=
                xf86Screens[0]->imageByteOrder)
                FatalError("Inconsistent display bitmapBitOrder.  Exiting\n");
            if (xf86Screens[i]->bitmapScanlinePad !=
                xf86Screens[0]->bitmapScanlinePad)
                FatalError
                    ("Inconsistent display bitmapScanlinePad.  Exiting\n");
            if (xf86Screens[i]->bitmapScanlineUnit !=
                xf86Screens[0]->bitmapScanlineUnit)
                FatalError
                    ("Inconsistent display bitmapScanlineUnit.  Exiting\n");
            if (xf86Screens[i]->bitmapBitOrder !=
                xf86Screens[0]->bitmapBitOrder)
                FatalError("Inconsistent display bitmapBitOrder.  Exiting\n");
        }

        /* Collect additional formats */
        for (i = 0; i < xf86NumScreens; i++) {
            for (j = 0; j < xf86Screens[i]->numFormats; j++) {
                for (k = 0;; k++) {
                    if (k >= numFormats) {
                        if (k >= MAXFORMATS)
                            FatalError("Too many pixmap formats!  Exiting\n");
                        formats[k] = xf86Screens[i]->formats[j];
                        numFormats++;
                        break;
                    }
                    if (formats[k].depth == xf86Screens[i]->formats[j].depth) {
                        if ((formats[k].bitsPerPixel ==
                             xf86Screens[i]->formats[j].bitsPerPixel) &&
                            (formats[k].scanlinePad ==
                             xf86Screens[i]->formats[j].scanlinePad))
                            break;
                        FatalError("Inconsistent pixmap format for depth %d.  Exiting\n", formats[k].depth);
                    }
                }
            }
        }
        formatsDone = TRUE;
    }
    else {
        /*
         * serverGeneration != 1; some OSs have to do things here, too.
         */
        if (xorgHWOpenConsole)
            xf86OpenConsole();

        /*
           should we reopen it here? We need to deal with an already opened
           device. We could leave this to the OS layer. For now we simply
           close it here
         */
        if (xf86OSPMClose)
            xf86OSPMClose();
        if ((xf86OSPMClose = xf86OSPMOpen()) != NULL)
            xf86MsgVerb(X_INFO, 3, "APM registered successfully\n");
        /* Make sure full I/O access is enabled */
        if (xorgHWAccess)
            xf86EnableIO();
    }

    if (xf86Info.vtno >= 0)
        AddCallback(&RootWindowFinalizeCallback, AddVTAtoms, NULL);

    if (SeatId)
        AddCallback(&RootWindowFinalizeCallback, AddSeatId, SeatId);

    /*
     * Use the previously collected parts to setup pScreenInfo
     */
    pScreenInfo->imageByteOrder = xf86Screens[0]->imageByteOrder;
    pScreenInfo->bitmapScanlinePad = xf86Screens[0]->bitmapScanlinePad;
    pScreenInfo->bitmapScanlineUnit = xf86Screens[0]->bitmapScanlineUnit;
    pScreenInfo->bitmapBitOrder = xf86Screens[0]->bitmapBitOrder;
    pScreenInfo->numPixmapFormats = numFormats;
    for (i = 0; i < numFormats; i++)
        pScreenInfo->formats[i] = formats[i];

    /* Make sure the server's VT is active */
    if (serverGeneration != 1) {
        xf86Resetting = TRUE;
        /* All screens are in the same state, so just check the first */
        if (!xf86VTOwner()) {
#ifdef HAS_USL_VTS
            ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ);
#endif
            input_lock();
            sigio_blocked = TRUE;
        }
    }

    for (i = 0; i < xf86NumScreens; i++)
        if (!xf86ColormapAllocatePrivates(xf86Screens[i]))
            FatalError("Cannot register DDX private keys");

    if (!dixRegisterPrivateKey(&xf86ScreenKeyRec, PRIVATE_SCREEN, 0))
        FatalError("Cannot register DDX private keys");

    for (i = 0; i < xf86NumScreens; i++) {
        xf86VGAarbiterLock(xf86Screens[i]);
        /*
         * Almost everything uses these defaults, and many of those that
         * don't, will wrap them.
         */
        xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess;
#ifdef XFreeXDGA
        xf86Screens[i]->SetDGAMode = xf86SetDGAMode;
#endif
        // AddScreen是 DIX 提供的桥梁:它创建 ScreenRec,然后回调具体显卡驱动的 ScreenInit。
        scr_index = AddScreen(xf86ScreenInit, argc, argv);
        xf86VGAarbiterUnlock(xf86Screens[i]);
        if (scr_index == i) {
            /*
             * Hook in our ScrnInfoRec, and initialise some other pScreen
             * fields.
             */
            dixSetPrivate(&screenInfo.screens[scr_index]->devPrivates,
                          xf86ScreenKey, xf86Screens[i]);
            xf86Screens[i]->pScreen = screenInfo.screens[scr_index];
            /* The driver should set this, but make sure it is set anyway */
            xf86Screens[i]->vtSema = TRUE;
        }
        else {
            /* This shouldn't normally happen */
            FatalError("AddScreen/ScreenInit failed for driver %d\n", i);
        }

        if (PictureGetSubpixelOrder(xf86Screens[i]->pScreen) == SubPixelUnknown) {
            xf86MonPtr DDC = (xf86MonPtr) (xf86Screens[i]->monitor->DDC);
            PictureSetSubpixelOrder(xf86Screens[i]->pScreen, DDC ? (DDC->features.input_type ? SubPixelHorizontalRGB : SubPixelNone) : SubPixelUnknown);
        }

        /*
         * If the driver hasn't set up its own RANDR support, install the
         * fallback support.
         */
        xf86EnsureRANDR(xf86Screens[i]->pScreen);
    }

    for (i = 0; i < xf86NumGPUScreens; i++) {
        ScrnInfoPtr pScrn = xf86GPUScreens[i];
        xf86VGAarbiterLock(pScrn);
        /*
         * Almost everything uses these defaults, and many of those that
         * don't, will wrap them.
         */
        pScrn->EnableDisableFBAccess = xf86EnableDisableFBAccess;
#ifdef XFreeXDGA
        pScrn->SetDGAMode = xf86SetDGAMode;
#endif
        scr_index = AddGPUScreen(xf86ScreenInit, argc, argv);
        xf86VGAarbiterUnlock(pScrn);
        if (scr_index == i) {
            dixSetPrivate(&screenInfo.gpuscreens[scr_index]->devPrivates, xf86ScreenKey, xf86GPUScreens[i]);
            pScrn->pScreen = screenInfo.gpuscreens[scr_index];
            /* The driver should set this, but make sure it is set anyway */
            pScrn->vtSema = TRUE;
        } else {
            FatalError("AddScreen/ScreenInit failed for gpu driver %d %d\n", i, scr_index);
        }
    }

    for (i = 0; i < xf86NumGPUScreens; i++) {
        int scrnum = xf86GPUScreens[i]->confScreen->screennum;
        AttachUnboundGPU(xf86Screens[scrnum]->pScreen, xf86GPUScreens[i]->pScreen);
    }
    xf86AutoConfigOutputDevices();
    xf86VGAarbiterWrapFunctions();

    if (sigio_blocked)
        input_unlock();
    xf86InitOrigins();
    xf86Resetting = FALSE;
    xf86Initialising = FALSE;
    RegisterBlockAndWakeupHandlers((ServerBlockHandlerProcPtr) NoopDDA, xf86Wakeup, NULL);
}

4、initInput
libinput / 具体输入驱动
→ QueuePointerEvents / QueueKeyboardEvents
→ mieqEnqueue
→ ProcessInputEvents
→ mieqProcessInputEvents
→ ProcessPointerEvent / ProcessKeyboardEvent
→ 命中测试、focus、grab、事件掩码与冒泡
→ DeliverEventsToWindow
→ WriteToClient

cpp 复制代码
void
InitInput(int argc, char **argv)
{
    InputInfoPtr *pInfo;
    DeviceIntPtr dev;
    xf86Info.vtRequestsPending = FALSE;

    /* Enable threaded input */
    InputThreadPreInit();
    mieqInit();

    /* Initialize all configured input devices */
    for (pInfo = xf86ConfigLayout.inputs; pInfo && *pInfo; pInfo++) {
        (*pInfo)->options =
            xf86AddNewOption((*pInfo)->options, "driver", (*pInfo)->driver);
        (*pInfo)->options =
            xf86AddNewOption((*pInfo)->options, "identifier", (*pInfo)->name);
        /* If one fails, the others will too */
        if (NewInputDeviceRequest((*pInfo)->options, NULL, &dev) == BadAlloc)
            break;
    }
    config_init();
}

5、dispatch函数
它是 X server 初始化完成后的主循环,核心职责是:

等待工作 → 处理输入事件 → 选择客户端 → 读取并执行 X 协议请求 → 发出响应,再进入下一轮。

cpp 复制代码
void
Dispatch(void)
{
    int result;
    ClientPtr client;
    long start_tick;
    nextFreeClientID = 1;
    nClients = 0;
    SmartScheduleSlice = SmartScheduleInterval;
    init_client_ready();

    while (!dispatchException) {
        // 有硬件输入
        if (InputCheckPending()) {
            ProcessInputEvents();
            FlushIfCriticalOutputPending();
        }

        // 统一处理网络、work queue、定时器、screen 的 block/wakeup hook、socket 与输入 FD
        if (!WaitForSomething(clients_are_ready()))
            continue;

        /*****************
         *  Handle events in round robin fashion, doing input between
         *  each round
         *****************/
        if (!dispatchException && clients_are_ready()) {
            client = SmartScheduleClient();
            isItTimeToYield = FALSE;
            start_tick = SmartScheduleTime;
            while (!isItTimeToYield) {
                if (InputCheckPending())
                    ProcessInputEvents();
                FlushIfCriticalOutputPending();
                if ((SmartScheduleTime - start_tick) >= SmartScheduleSlice)
                {
                    /* Penalize clients which consume ticks */
                    if (client->smart_priority > SMART_MIN_PRIORITY)
                        client->smart_priority--;
                    break;
                }

                /* now, finally, deal with client requests */
                result = ReadRequestFromClient(client);
                if (result == 0)
                    break;
                else if (result == -1) {
                    CloseDownClient(client);
                    break;
                }

                client->sequence++;
                client->majorOp = ((xReq *) client->requestBuffer)->reqType;
                client->minorOp = 0;
                if (client->majorOp >= EXTENSION_BASE) {
                    ExtensionEntry *ext = GetExtensionEntry(client->majorOp);
                    if (ext)
                        client->minorOp = ext->MinorOpcode(client);
                }
#ifdef XSERVER_DTRACE
                if (XSERVER_REQUEST_START_ENABLED())
                    XSERVER_REQUEST_START(LookupMajorName(client->majorOp),client->majorOp, ((xReq *) client->requestBuffer)->length, client->index, client->requestBuffer);
#endif
                if (result < 0 || result > (maxBigRequestSize << 2))
                    result = BadLength;
                else {
                    result = XaceHookDispatch(client, client->majorOp);
                    if (result == Success) {
                        currentClient = client;
                        result = (*client->requestVector[client->majorOp]) (client);
                        currentClient = NULL;
                    }
                }
                if (!SmartScheduleSignalEnable)
                    SmartScheduleTime = GetTimeInMillis();

#ifdef XSERVER_DTRACE
                if (XSERVER_REQUEST_DONE_ENABLED())
                    XSERVER_REQUEST_DONE(LookupMajorName(client->majorOp), client->majorOp, client->sequence, client->index, result);
#endif
                if (client->noClientException != Success) {
                    CloseDownClient(client);
                    break;
                }
                else if (result != Success) {
                    SendErrorToClient(client, client->majorOp, client->minorOp, client->errorValue, result);
                    break;
                }
            }
            FlushAllOutput();
            if (client == SmartLastClient)
                client->smart_stop_tick = SmartScheduleTime;
        }
        dispatchException &= ~DE_PRIORITYCHANGE;
    }
#if defined(DDXBEFORERESET)
    ddxBeforeReset();
#endif
    KillAllClients();
    dispatchException &= ~DE_RESET;
    SmartScheduleLatencyLimited = 0;
    ResetOsBuffers();
}
相关推荐
ghking15 个月前
ubuntu下部署大模型显存被其它程序占用问题解决
ubuntu·大模型·gnome·nvidia-smi·xorg·remote-desktop
冰山一脚20136 个月前
linux显示渲染框架笔记
drm·xorg·x11
ordinary_brony3 年前
Paddle2.5+PaddleDetect安装
linux·paddlepaddle·cuda·xorg