[PATCH xserver 18/23] dix: Use list for ready clients

Keith Packard keithp at keithp.com
Thu May 26 23:59:53 UTC 2016


This converts the dispatch loop into using a list of ready clients
instead of an array. This changes the WaitForSomething API so that it
notifies DIX when a client becomes ready to read, instead of returning
the set of ready clients.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 dix/dispatch.c      | 114 +++++++++++++++++++++++++++++++++++++---------------
 include/dixstruct.h |  15 +++++++
 include/os.h        |   3 +-
 os/WaitFor.c        |  36 ++++++++---------
 os/connection.c     |   5 ++-
 5 files changed, 118 insertions(+), 55 deletions(-)

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 3237883..a61d7a4 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -240,21 +240,76 @@ long SmartLastPrint;
 
 void Dispatch(void);
 
-static int
-SmartScheduleClient(int *clientReady, int nready)
+static struct xorg_list ready_clients;
+static struct xorg_list saved_ready_clients;
+
+static void
+init_client_ready(void)
+{
+    xorg_list_init(&ready_clients);
+    xorg_list_init(&saved_ready_clients);
+}
+
+Bool
+clients_are_ready(void)
+{
+    return !xorg_list_is_empty(&ready_clients);
+}
+
+/* Client has requests queued or data on the network */
+void
+mark_client_ready(ClientPtr client)
+{
+    if (xorg_list_is_empty(&client->ready))
+        xorg_list_append(&client->ready, &ready_clients);
+}
+
+/* Client has no requests queued and no data on network */
+void
+mark_client_not_ready(ClientPtr client)
+{
+    xorg_list_del(&client->ready);
+}
+
+static void
+mark_client_grab(ClientPtr grab)
+{
+    ClientPtr   client, tmp;
+
+    xorg_list_for_each_entry_safe(client, tmp, &ready_clients, ready) {
+        if (client != grab) {
+            xorg_list_del(&client->ready);
+            xorg_list_append(&client->ready, &saved_ready_clients);
+        }
+    }
+}
+
+static void
+mark_client_ungrab(void)
+{
+    ClientPtr   client, tmp;
+
+    xorg_list_for_each_entry_safe(client, tmp, &saved_ready_clients, ready) {
+        xorg_list_del(&client->ready);
+        xorg_list_append(&client->ready, &ready_clients);
+    }
+}
+
+static ClientPtr
+SmartScheduleClient(void)
 {
-    int i;
-    int client;
     ClientPtr pClient, best = NULL;
     int bestRobin, robin;
     long now = SmartScheduleTime;
     long idle;
+    int nready = 0;
 
     bestRobin = 0;
     idle = 2 * SmartScheduleSlice;
-    for (i = 0; i < nready; i++) {
-        client = clientReady[i];
-        pClient = clients[client];
+
+    xorg_list_for_each_entry(pClient, &ready_clients, ready) {
+        nready++;
+
         /* Praise clients which haven't run in a while */
         if ((now - pClient->smart_stop_tick) >= idle) {
             if (pClient->smart_priority < 0)
@@ -279,12 +334,12 @@ SmartScheduleClient(int *clientReady, int nready)
         }
 #ifdef SMART_DEBUG
         if ((now - SmartLastPrint) >= 5000)
-            fprintf(stderr, " %2d: %3d", client, pClient->smart_priority);
+            fprintf(stderr, " %2d: %3d", pClient->index, pClient->smart_priority);
 #endif
     }
 #ifdef SMART_DEBUG
     if ((now - SmartLastPrint) >= 5000) {
-        fprintf(stderr, " use %2d\n", best);
+        fprintf(stderr, " use %2d\n", best->index);
         SmartLastPrint = now;
     }
 #endif
@@ -292,9 +347,9 @@ SmartScheduleClient(int *clientReady, int nready)
     /*
      * Set current client pointer
      */
-    if (SmartLastClient != pClient) {
-        pClient->smart_start_tick = now;
-        SmartLastClient = pClient;
+    if (SmartLastClient != best) {
+        best->smart_start_tick = now;
+        SmartLastClient = best;
     }
     /*
      * Adjust slice
@@ -313,7 +368,7 @@ SmartScheduleClient(int *clientReady, int nready)
     else {
         SmartScheduleSlice = SmartScheduleInterval;
     }
-    return best->index;
+    return best;
 }
 
 void
@@ -336,44 +391,34 @@ DisableLimitedSchedulingLatency(void)
 void
 Dispatch(void)
 {
-    int *clientReady;           /* array of request ready clients */
     int result;
     ClientPtr client;
-    int nready;
     HWEventQueuePtr *icheck = checkForInput;
     long start_tick;
 
     nextFreeClientID = 1;
     nClients = 0;
 
-    clientReady = xallocarray(MaxClients, sizeof(int));
-    if (!clientReady)
-        return;
-
     SmartScheduleSlice = SmartScheduleInterval;
+    init_client_ready();
+
     while (!dispatchException) {
         if (*icheck[0] != *icheck[1]) {
             ProcessInputEvents();
             FlushIfCriticalOutputPending();
         }
 
-        nready = WaitForSomething(clientReady);
+        if (!WaitForSomething(clients_are_ready()))
+            continue;
 
-        if (nready) {
-            clientReady[0] = SmartScheduleClient(clientReady, nready);
-            nready = 1;
-        }
        /*****************
 	*  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;
-            }
+        if (!dispatchException && clients_are_ready()) {
+            client = SmartScheduleClient();
+
             isItTimeToYield = FALSE;
 
             start_tick = SmartScheduleTime;
@@ -393,6 +438,7 @@ Dispatch(void)
                 /* now, finally, deal with client requests */
                 result = ReadRequestFromClient(client);
                 if (result <= 0) {
+                    mark_client_not_ready(client);
                     if (result < 0)
                         CloseDownClient(client);
                     break;
@@ -446,8 +492,7 @@ Dispatch(void)
                 }
             }
             FlushAllOutput();
-            client = clients[clientReady[nready]];
-            if (client)
+            if (client == SmartLastClient)
                 client->smart_stop_tick = SmartScheduleTime;
         }
         dispatchException &= ~DE_PRIORITYCHANGE;
@@ -456,7 +501,6 @@ Dispatch(void)
     ddxBeforeReset();
 #endif
     KillAllClients();
-    free(clientReady);
     dispatchException &= ~DE_RESET;
     SmartScheduleLatencyLimited = 0;
     ResetOsBuffers();
@@ -1056,6 +1100,7 @@ ProcGrabServer(ClientPtr client)
         return rc;
     grabState = GrabActive;
     grabClient = client;
+    mark_client_grab(client);
 
     if (ServerGrabCallback) {
         ServerGrabInfoRec grabinfo;
@@ -1075,6 +1120,7 @@ UngrabServer(ClientPtr client)
 
     grabState = GrabNone;
     ListenToAllClients();
+    mark_client_ungrab();
     for (i = mskcnt; --i >= 0 && !grabWaiters[i];);
     if (i >= 0) {
         i <<= 5;
@@ -3366,6 +3412,7 @@ CloseDownClient(ClientPtr client)
         if (grabState != GrabNone && grabClient == client) {
             UngrabServer(client);
         }
+        mark_client_not_ready(client);
         BITCLEAR(grabWaiters, client->index);
         DeleteClientFromAnySelections(client);
         ReleaseActiveGrabs(client);
@@ -3455,6 +3502,7 @@ void
 InitClient(ClientPtr client, int i, void *ospriv)
 {
     client->index = i;
+    xorg_list_init(&client->ready);
     client->clientAsMask = ((Mask) i) << CLIENTOFFSET;
     client->closeDownMode = i ? DestroyAll : RetainPermanent;
     client->requestVector = InitialVector;
diff --git a/include/dixstruct.h b/include/dixstruct.h
index 8e70ae1..1f38349 100644
--- a/include/dixstruct.h
+++ b/include/dixstruct.h
@@ -76,6 +76,7 @@ typedef struct _saveSet {
 typedef struct _Client {
     void *requestBuffer;
     void *osPrivate;             /* for OS layer, including scheduler */
+    struct xorg_list ready;      /* List of clients ready to run */
     Mask clientAsMask;
     short index;
     unsigned char majorOp, minorOp;
@@ -138,6 +139,20 @@ extern Bool SmartScheduleSignalEnable;
 extern void SmartScheduleStartTimer(void);
 extern void SmartScheduleStopTimer(void);
 
+/* Client has requests queued or data on the network */
+void mark_client_ready(ClientPtr client);
+
+/* Client has no requests queued and no data on network */
+void mark_client_not_ready(ClientPtr client);
+
+static inline Bool client_is_ready(ClientPtr client)
+{
+    return !xorg_list_is_empty(&client->ready);
+}
+
+Bool
+clients_are_ready(void);
+
 #define SMART_MAX_PRIORITY  (20)
 #define SMART_MIN_PRIORITY  (-20)
 
diff --git a/include/os.h b/include/os.h
index 25e02bf..2d71c91 100644
--- a/include/os.h
+++ b/include/os.h
@@ -93,8 +93,7 @@ extern _X_EXPORT void (*OsVendorVErrorFProc) (const char *,
 _X_ATTRIBUTE_PRINTF(1, 0);
 #endif
 
-extern _X_EXPORT int WaitForSomething(int *     /*pClientsReady */
-    );
+extern _X_EXPORT Bool WaitForSomething(Bool clients_are_ready);
 
 extern _X_EXPORT int ReadRequestFromClient(ClientPtr /*client */ );
 
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 0ba1d6b..ef4ebb5 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -142,8 +142,8 @@ static volatile OsTimerPtr timers = NULL;
  *     pClientsReady is an array to store ready client->index values into.
  *****************/
 
-int
-WaitForSomething(int *pClientsReady)
+Bool
+WaitForSomething(Bool are_ready)
 {
     int i;
     struct timeval waittime, *wt;
@@ -154,7 +154,6 @@ WaitForSomething(int *pClientsReady)
     int selecterr;
     static int nready;
     CARD32 now = 0;
-    Bool someReady = FALSE;
     Bool someNotifyWriteReady = FALSE;
 
     FD_ZERO(&clientsReadable);
@@ -174,11 +173,9 @@ WaitForSomething(int *pClientsReady)
         /* deal with any blocked jobs */
         if (workQueue)
             ProcessWorkQueue();
-        if (XFD_ANYSET(&ClientsWithInput)) {
+
+        if (are_ready) {
             timeout = 0;
-            someReady = TRUE;
-        }
-        if (someReady) {
             XFD_COPYSET(&AllSockets, &LastSelectMask);
             XFD_UNSET(&LastSelectMask, &ClientsWithInput);
         }
@@ -227,12 +224,12 @@ WaitForSomething(int *pClientsReady)
         WakeupHandler(i);
         if (i <= 0) {           /* An error or timeout occurred */
             if (dispatchException)
-                return 0;
+                return FALSE;
             if (i < 0) {
                 if (selecterr == EBADF) {       /* Some client disconnected */
                     CheckConnections();
                     if (!XFD_ANYSET(&AllClients))
-                        return 0;
+                        return FALSE;
                 }
                 else if (selecterr == EINVAL) {
                     FatalError("WaitForSomething(): select: %s\n",
@@ -243,7 +240,7 @@ WaitForSomething(int *pClientsReady)
                            strerror(selecterr));
                 }
             }
-            else if (someReady) {
+            else if (are_ready) {
                 /*
                  * If no-one else is home, bail quickly
                  */
@@ -252,7 +249,7 @@ WaitForSomething(int *pClientsReady)
                 break;
             }
             if (*checkForInput[0] != *checkForInput[1])
-                return 0;
+                return FALSE;
 
             if (timers) {
                 int expired = 0;
@@ -267,7 +264,7 @@ WaitForSomething(int *pClientsReady)
                         DoTimer(timers, now, &timers);
                     OsReleaseSignals();
 
-                    return 0;
+                    return FALSE;
                 }
             }
         }
@@ -288,12 +285,11 @@ WaitForSomething(int *pClientsReady)
                             DoTimer(timers, now, &timers);
                         OsReleaseSignals();
 
-                        return 0;
+                        return FALSE;
                     }
                 }
             }
-            if (someReady)
-                XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
+
             if (AnyWritesPending) {
                 XFD_ANDSET(&clientsWritable, &LastSelectWriteMask, &ClientsWriteBlocked);
                 if (XFD_ANYSET(&clientsWritable)) {
@@ -316,11 +312,12 @@ WaitForSomething(int *pClientsReady)
             if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady)
                 HandleNotifyFds();
 
-            if (XFD_ANYSET(&clientsReadable))
+            if (are_ready || XFD_ANYSET(&clientsReadable))
                 break;
+
             /* check here for DDXes that queue events during Block/Wakeup */
             if (*checkForInput[0] != *checkForInput[1])
-                return 0;
+                return FALSE;
         }
     }
 
@@ -345,7 +342,8 @@ WaitForSomething(int *pClientsReady)
             curclient = XFD_FD(&savedClientsReadable, i);
             client_index = GetConnectionTranslation(curclient);
 #endif
-            pClientsReady[nready++] = client_index;
+            nready++;
+            mark_client_ready(clients[client_index]);
 #ifndef WIN32
             clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
         }
@@ -358,7 +356,7 @@ WaitForSomething(int *pClientsReady)
     if (nready)
         SmartScheduleStartTimer();
 
-    return nready;
+    return TRUE;
 }
 
 void
diff --git a/os/connection.c b/os/connection.c
index cfe641a..d4e367a 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -1230,6 +1230,7 @@ IgnoreClient(ClientPtr client)
         return;
 
     isItTimeToYield = TRUE;
+    mark_client_not_ready(client);
     if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
         if (FD_ISSET(connection, &ClientsWithInput))
             FD_SET(connection, &IgnoredClientsWithInput);
@@ -1271,8 +1272,10 @@ AttendClient(ClientPtr client)
         FD_SET(connection, &AllClients);
         FD_SET(connection, &AllSockets);
         FD_SET(connection, &LastSelectMask);
-        if (FD_ISSET(connection, &IgnoredClientsWithInput))
+        if (FD_ISSET(connection, &IgnoredClientsWithInput)) {
             FD_SET(connection, &ClientsWithInput);
+            mark_client_ready(client);
+        }
     }
     else {
         FD_SET(connection, &SavedAllClients);
-- 
2.8.0.rc3



More information about the xorg-devel mailing list