目录
-
-
- 简介
- 注册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。
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();
}