天天看点

Xorg Handler简介

目录

      • 简介
      • 注册BlockHandler和WakeupHandler
        • RegisterBlockAndWakeupHandlers
        • 注册到Screen
      • 注册InputHandler
      • 注册GeneralHandler
      • Handler的执行
        • BlockHandler函数
        • WakeupHandler函数
      • xf86Wakeup函数

简介

Xorg Handler用于处理各种类型的回调函数,Xorg一共支持四种类型的Handler:

  • BlockHandler: 在阻塞之前调用;
  • WakeupHandler: 在唤醒之后调用;
  • InputHandler: 用于键盘鼠标等输入设备;
  • GeneralHandler: 用于其它类型的设备;

其中BlockHandler和WakeupHandler属于同一种类型,它们的回调函数不需要关联设备文件句柄,并且一旦注册上就会无条件执行。

InputHandler和GeneralHandler属于另一种类型,它们的回调函数需要关联到某一个设备句柄(例如键盘设备文件),当设备句柄有数据到达时,可以马上唤醒阻塞中的Xorg,并且只有在设备句柄可读/可写时,对应的回调函数才会执行。

注册BlockHandler和WakeupHandler

RegisterBlockAndWakeupHandlers

BlockHandler和WakeupHandler通过调用RegisterBlockAndWakeupHandlers函数注册,该函数同时注册两个回调函数,通过往static数组handlers增加一个成员实现:

Bool
RegisterBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
                               WakeupHandlerProcPtr wakeupHandler,
                               void *blockData)
{
    BlockHandlerPtr new;

    if (numHandlers >= sizeHandlers) {
        new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
                                        sizeof(BlockHandlerRec));
        if (!new)
            return FALSE;
        handlers = new;
        sizeHandlers = numHandlers + 1;
    }
    handlers[numHandlers].BlockHandler = blockHandler;
    handlers[numHandlers].WakeupHandler = wakeupHandler;
    handlers[numHandlers].blockData = blockData;
    handlers[numHandlers].deleted = FALSE;
    numHandlers = numHandlers + 1;
    return TRUE;
}
           

注册到Screen

除了调用上面的函数注册到handlers,也可以通过直接修改指针注册到Screen,典型代码如下:

/*
 * Setup points to the block and wakeup handlers.  Pass a pointer
 * to the current screen as pWakeupdata.
 */
pScreen->BlockHandler = winBlockHandler;
pScreen->WakeupHandler = winWakeupHandler;
           

如果使用直接修改指针的方式注册,需要在修改之前保存原始指针,退出时进行还原。这两种注册方式使用场景也有差别,第二种注册的回调函数与对应的Screen绑定,第一种注册方式没有绑定。

注册InputHandler

InputHandler通过调用xf86AddInputHandler函数注册,该函数在InputHandlers链表中增加一个成员。

static void *
addInputHandler(int fd, InputHandlerProc proc, void *data)
{
    IHPtr ih;

    if (fd < 0 || !proc)
        return NULL;

    ih = calloc(sizeof(*ih), 1);
    if (!ih)
        return NULL;

    ih->fd = fd;
    ih->ihproc = proc;
    ih->data = data;
    ih->enabled = TRUE;

    ih->next = InputHandlers;
    InputHandlers = ih;

    return ih;
}

void *
xf86AddInputHandler(int fd, InputHandlerProc proc, void *data)
{
    IHPtr ih = addInputHandler(fd, proc, data);

    if (ih) {
        AddEnabledDevice(fd);
        ih->is_input = TRUE;
    }
    return ih;
}
           

注册GeneralHandler

GeneralHandler通过调用xf86AddGeneralHandler函数注册。该函数与xf86AddInputHandler一样,内部也是通过调用addInputHandler实现,不同的是InputHandler被标记为输入设备,除此之外没有其它差别。

void *
xf86AddGeneralHandler(int fd, InputHandlerProc proc, void *data)
{
    IHPtr ih = addInputHandler(fd, proc, data);

    if (ih)
        AddGeneralSocket(fd);
    return ih;
}
           

Handler的执行

Handler执行流程如下图所示,在WaitForSomething函数中先调用BlockHandler执行所有block类型的handler,然后执行select等待输入事件,select阻塞结束后执行WakeupHandler执行所有wakeup类型的handler。InputHandler和GeneralHandler由xf86Wakeup函数执行,该函数在Xorg初始化时会被注册为一个WakeupHandler。

Xorg Handler简介

BlockHandler函数

void
BlockHandler(void *pTimeout, void *pReadmask)
{
    int i, j;

    ++inHandler;
    for (i = 0; i < screenInfo.numScreens; i++)
        (*screenInfo.screens[i]->BlockHandler) (screenInfo.screens[i],
                                                pTimeout, pReadmask);
    for (i = 0; i < screenInfo.numGPUScreens; i++)
        (*screenInfo.gpuscreens[i]->BlockHandler) (screenInfo.gpuscreens[i],
                                                   pTimeout, pReadmask);
    for (i = 0; i < numHandlers; i++)
        if (!handlers[i].deleted)
            (*handlers[i].BlockHandler) (handlers[i].blockData,
                                         pTimeout, pReadmask);
    if (handlerDeleted) {
        for (i = 0; i < numHandlers;)
            if (handlers[i].deleted) {
                for (j = i; j < numHandlers - 1; j++)
                    handlers[j] = handlers[j + 1];
                numHandlers--;
            }
            else
                i++;
        handlerDeleted = FALSE;
    }
    --inHandler;
}
           

WakeupHandler函数

void
WakeupHandler(int result, void *pReadmask)
{
    int i, j;

    ++inHandler;
    for (i = numHandlers - 1; i >= 0; i--)
        if (!handlers[i].deleted)
            (*handlers[i].WakeupHandler) (handlers[i].blockData,
                                          result, pReadmask);
    for (i = 0; i < screenInfo.numScreens; i++)
        (*screenInfo.screens[i]->WakeupHandler) (screenInfo.screens[i],
                                                 result, pReadmask);
    for (i = 0; i < screenInfo.numGPUScreens; i++)
        (*screenInfo.gpuscreens[i]->WakeupHandler) (screenInfo.gpuscreens[i],
                                                    result, pReadmask);
    if (handlerDeleted) {
        for (i = 0; i < numHandlers;)
            if (handlers[i].deleted) {
                for (j = i; j < numHandlers - 1; j++)
                    handlers[j] = handlers[j + 1];
                numHandlers--;
            }
            else
                i++;
        handlerDeleted = FALSE;
    }
    --inHandler;
}
           

xf86Wakeup函数

Xorg在初始化时调用

RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, xf86Wakeup, NULL);

注册xf86Wakeup。

void
xf86Wakeup(void *blockData, int err, void *pReadmask)
{
    fd_set *LastSelectMask = (fd_set *) pReadmask;
    fd_set devicesWithInput;
    InputInfoPtr pInfo;

    if (err >= 0) {

        XFD_ANDSET(&devicesWithInput, LastSelectMask, &EnabledDevices);
        if (XFD_ANYSET(&devicesWithInput)) {
            pInfo = xf86InputDevs;
            while (pInfo) {
                if (pInfo->read_input && pInfo->fd >= 0 &&
                    (FD_ISSET(pInfo->fd, &devicesWithInput) != 0)) {
                    OsBlockSIGIO();

                    /*
                     * Remove the descriptior from the set because more than one
                     * device may share the same file descriptor.
                     */
                    FD_CLR(pInfo->fd, &devicesWithInput);

                    pInfo->read_input(pInfo);
                    OsReleaseSIGIO();
                }
                pInfo = pInfo->next;
            }
        }
    }

    if (err >= 0) {             /* we don't want the handlers called if select() */
        IHPtr ih, ih_tmp;       /* returned with an error condition, do we?      */

        nt_list_for_each_entry_safe(ih, ih_tmp, InputHandlers, next) {
            if (ih->enabled && ih->fd >= 0 && ih->ihproc &&
                (FD_ISSET(ih->fd, ((fd_set *) pReadmask)) != 0)) {
                ih->ihproc(ih->fd, ih->data);
            }
        }
    }

    if (xf86VTSwitchPending())
        xf86VTSwitch();
}
           
Xorg Handler简介

继续阅读