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. |