Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

Dispatch()

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.