Hands-on Projects for the Linux Graphics Subsystem
|
Dispatch() the main X server iteration loop is a dix (device independed x) routine, which is implemented as:
void
Dispatch(void)
{
register int *clientReady; /* array of request ready clients */
register int result;
register ClientPtr client;
register int nready;
register HWEventQueuePtr* icheck = checkForInput;
#ifdef SMART_SCHEDULE
long start_tick;
#endif
nextFreeClientID = 1;
InitSelections();
nClients = 0;
clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients);
if (!clientReady)
return;
while (!dispatchException)
{
if (*icheck[0] != *icheck[1])
{
ProcessInputEvents();
FlushIfCriticalOutputPending();
}
nready = WaitForSomething(clientReady);
#ifdef SMART_SCHEDULE
if (nready && !SmartScheduleDisable)
{
clientReady[0] = SmartScheduleClient (clientReady, nready);
nready = 1;
}
#endif
/*****************
* Handle events in round robin fashion, doing input between
* each round
*****************/
while (!dispatchException && (--nready >= 0))
{
client = clients[clientReady[nready]];
if (! client)
{
/* KillClient can cause this to happen */
continue;
}
/* GrabServer activation can cause this to be true */
if (grabState == GrabKickout)
{
grabState = GrabActive;
break;
}
isItTimeToYield = FALSE;
requestingClient = client;
#ifdef SMART_SCHEDULE
start_tick = SmartScheduleTime;
#endif
while (!isItTimeToYield)
{
if (*icheck[0] != *icheck[1])
{
ProcessInputEvents();
FlushIfCriticalOutputPending();
}
#ifdef SMART_SCHEDULE
if (!SmartScheduleDisable &&
(SmartScheduleTime - start_tick) >= SmartScheduleSlice)
{
/* Penalize clients which consume ticks */
if (client->smart_priority > SMART_MIN_PRIORITY)
client->smart_priority--;
break;
}
#endif
/* now, finally, deal with client requests */
result = ReadRequestFromClient(client);
if (result <= 0)
{
if (result < 0)
CloseDownClient(client);
break;
}
client->sequence++;
#ifdef DEBUG
if (client->requestLogIndex == MAX_REQUEST_LOG)
client->requestLogIndex = 0;
client->requestLog[client->requestLogIndex] = MAJOROP;
client->requestLogIndex++;
#endif
if (result > (maxBigRequestSize << 2))
result = BadLength;
else
result = (* client->requestVector[MAJOROP])(client);
if (result != Success)
{
if (client->noClientException != Success)
CloseDownClient(client);
else
SendErrorToClient(client, MAJOROP,
MinorOpcodeOfRequest(client),
client->errorValue, result);
break;
}
#ifdef DAMAGEEXT
FlushIfCriticalOutputPending ();
#endif
}
FlushAllOutput();
#ifdef SMART_SCHEDULE
client = clients[clientReady[nready]];
if (client)
client->smart_stop_tick = SmartScheduleTime;
#endif
requestingClient = NULL;
}
dispatchException &= ~DE_PRIORITYCHANGE;
}
#if defined(DDXBEFORERESET)
ddxBeforeReset ();
#endif
KillAllClients();
DEALLOCATE_LOCAL(clientReady);
dispatchException &= ~DE_RESET;
}
|
clientReady the integer array allocated as:
clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients);
|
is a list of indexes (client->index) for clients with data ready to be read or processed.
Struct _Client is defined in dixstruct.h as:
typedef struct _Client {
int index;
Mask clientAsMask;
pointer requestBuffer;
pointer osPrivate; /* for OS layer, including scheduler */
Bool swapped;
ReplySwapPtr pSwapReplyFunc;
XID errorValue;
int sequence;
int closeDownMode;
int clientGone;
int noClientException; /* this client died or needs to be
* killed */
DrawablePtr lastDrawable;
Drawable lastDrawableID;
GCPtr lastGC;
GContext lastGCID;
SaveSetElt *saveSet;
int numSaved;
pointer screenPrivate[MAXSCREENS];
int (**requestVector) (
ClientPtr /* pClient */);
CARD32 req_len; /* length of current request */
Bool big_requests; /* supports large requests */
int priority;
ClientState clientState;
DevUnion *devPrivates;
#ifdef XKB
unsigned short xkbClientFlags;
unsigned short mapNotifyMask;
unsigned short newKeyboardNotifyMask;
unsigned short vMajor,vMinor;
KeyCode minKC,maxKC;
#endif
#ifdef DEBUG
unsigned char requestLog[MAX_REQUEST_LOG];
int requestLogIndex;
#endif
#ifdef LBX
int (*readRequest)(ClientPtr /*client*/);
#endif
unsigned long replyBytesRemaining;
#ifdef XCSECURITY
XID authId;
unsigned int trustLevel;
pointer (* CheckAccess)(
ClientPtr /*pClient*/,
XID /*id*/,
RESTYPE /*classes*/,
Mask /*access_mode*/,
pointer /*resourceval*/);
#endif
#ifdef XAPPGROUP
struct _AppGroupRec* appgroup;
#endif
struct _FontResolution * (*fontResFunc) ( /* no need for font.h */
ClientPtr /* pClient */,
int * /* num */);
#ifdef SMART_SCHEDULE
int smart_priority;
long smart_start_tick;
long smart_stop_tick;
long smart_check_tick;
#endif
} ClientRec;
|
MAXCLIENTS the max client number is defined in misc.h as:
#define MAXCLIENTS 256 |
To study the Dispatch() loop the following over-simplified code will be used to locate the main parts of this routine:
while (!dispatchException)
{
if (*icheck[0] != *icheck[1])
{
ProcessInputEvents();
FlushIfCriticalOutputPending();
}
nready = WaitForSomething(clientReady);
while (!dispatchException && (--nready >= 0))
{
while (!isItTimeToYield)
{
if (*icheck[0] != *icheck[1])
{
ProcessInputEvents();
FlushIfCriticalOutputPending();
}
result = ReadRequestFromClient(client);
result = (* client->requestVector[MAJOROP])(client);
}
FlushAllOutput();
}
dispatchException &= ~DE_PRIORITYCHANGE;
}
|
The main parts of Dispatch are explained as follows:
while (!dispatchException) |
| As we notice Dispatch() uses a triple 'while' loop. The first should run infinitely for the life of the X Server and breaks out only in special conditions when a 'dispatchException' is raised. Such a condition would be the receipt of a SIGTERM or a SIGINT singal from the X Server. In this case GiveUp() handles those signals and sets dispatchException to DE_TERMINATE and also isItTimeToYield (see next paragraphs) to TRUE. |
if (*icheck[0] != *icheck[1])
{
ProcessInputEvents();
FlushIfCriticalOutputPending();
}
|
| Twice in the Dispatch the ProcessInputEvents() and FlushIfCriticalOutputPending() pair are called. Once before waiting for ready clients and once before handling requests from a specific client. Those routines are explained in section 3.2.5.1. |
nready = WaitForSomething(clientReady); |
| WaitForSomething() returns at nready the count of the client indexes and also fills pClientsReady with the ready client's indexes. It is explained in section 3.2.5.2. |
while (!isItTimeToYield) |
isItTimeToYield is set in ReadRequestFromClient() with YieldControl, defined in io.c as:
#define YieldControl() \
{ isItTimeToYield = TRUE; \
timesThisConnection = 0; }
|
result = ReadRequestFromClient(client); result = (* client->requestVector[MAJOROP])(client); } |
| Those two lines are actually the core of the X server where the client requests are read and dispatched. They are described in section 3.2.5.3. |
FlushAllOutput();
|
| FlushAllOutput() is covered in section 3.2.5.4. |