[PATCH xserver 17/25] os: use poll(2) instead of select(2)

Keith Packard keithp at keithp.com
Wed May 25 05:38:54 UTC 2016


This leaves all of the select file descriptor bashing in place, and
just adds the necessary hooks to compute the poll data as well.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 os/WaitFor.c    | 143 ++++++++++++++-----------------------
 os/connection.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 os/osdep.h      |  27 +++++++
 3 files changed, 277 insertions(+), 107 deletions(-)

diff --git a/os/WaitFor.c b/os/WaitFor.c
index e78e358..eff2f70 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -148,20 +148,19 @@ WaitForSomething(Bool clients_are_ready)
     int i;
     struct timeval waittime, *wt;
     INT32 timeout = 0;
-    fd_set clientsReadable;
-    fd_set clientsWritable;
-    int curclient;
-    int selecterr;
-    static int nready;
+    int pollerr;
+    static Bool clients_were_ready;
+    Bool timer_is_running;
     CARD32 now = 0;
-    Bool someNotifyWriteReady = FALSE;
 
-    FD_ZERO(&clientsReadable);
-    FD_ZERO(&clientsWritable);
+    timer_is_running = clients_were_ready;
 
-    if (nready)
+    if (clients_were_ready && !clients_are_ready) {
+        timer_is_running = FALSE;
         SmartScheduleStopTimer();
-    nready = 0;
+    }
+
+    clients_were_ready = FALSE;
 
 #ifdef BUSFAULT
     busfault_check();
@@ -178,8 +177,6 @@ WaitForSomething(Bool clients_are_ready)
             waittime.tv_sec = 0;
             waittime.tv_usec = 0;
             wt = &waittime;
-            XFD_COPYSET(&AllSockets, &LastSelectMask);
-            XFD_UNSET(&LastSelectMask, &ClientsWithInput);
         }
         else {
             wt = NULL;
@@ -201,7 +198,6 @@ WaitForSomething(Bool clients_are_ready)
                     wt = &waittime;
                 }
             }
-            XFD_COPYSET(&AllSockets, &LastSelectMask);
         }
 
         BlockHandler(&wt);
@@ -210,40 +206,37 @@ WaitForSomething(Bool clients_are_ready)
         /* keep this check close to select() call to minimize race */
         if (dispatchException)
             i = -1;
-        else if (AnyWritesPending) {
-            XFD_COPYSET(&ClientsWriteBlocked, &LastSelectWriteMask);
-            XFD_ORSET(&LastSelectWriteMask, &NotifyWriteFds, &LastSelectWriteMask);
-            i = Select(MaxClients, &LastSelectMask, &LastSelectWriteMask, NULL, wt);
-        }
-        else {
-            i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
+        else
+        {
+            int poll_timeout = -1;
+
+            if (wt)
+                poll_timeout = wt->tv_sec * 1000 + wt->tv_usec / 1000;
+            i = poll(poll_fds, poll_fds_num, poll_timeout);
         }
-        selecterr = GetErrno();
+        pollerr = GetErrno();
         WakeupHandler(i);
         if (i <= 0) {           /* An error or timeout occurred */
             if (dispatchException)
                 return FALSE;
             if (i < 0) {
-                if (selecterr == EBADF) {       /* Some client disconnected */
+                if (pollerr == EBADF) {       /* Some client disconnected */
                     CheckConnections();
-                    if (!XFD_ANYSET(&AllClients))
-                        return FALSE;
+                    return FALSE;
                 }
-                else if (selecterr == EINVAL) {
-                    FatalError("WaitForSomething(): select: %s\n",
-                               strerror(selecterr));
+                else if (pollerr == EINVAL) {
+                    FatalError("WaitForSomething(): poll: %s\n",
+                               strerror(pollerr));
                 }
-                else if (selecterr != EINTR && selecterr != EAGAIN) {
-                    ErrorF("WaitForSomething(): select: %s\n",
-                           strerror(selecterr));
+                else if (pollerr != EINTR && pollerr != EAGAIN) {
+                    ErrorF("WaitForSomething(): poll: %s\n",
+                           strerror(pollerr));
                 }
             }
             else if (clients_are_ready) {
                 /*
                  * If no-one else is home, bail quickly
                  */
-                XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
-                XFD_COPYSET(&ClientsWithInput, &clientsReadable);
                 break;
             }
             if (*checkForInput[0] != *checkForInput[1])
@@ -267,7 +260,7 @@ WaitForSomething(Bool clients_are_ready)
             }
         }
         else {
-            fd_set tmp_set;
+            int p;
 
             if (*checkForInput[0] == *checkForInput[1]) {
                 if (timers) {
@@ -287,72 +280,44 @@ WaitForSomething(Bool clients_are_ready)
                     }
                 }
             }
-
-            if (AnyWritesPending) {
-                XFD_ANDSET(&clientsWritable, &LastSelectWriteMask, &ClientsWriteBlocked);
-                if (XFD_ANYSET(&clientsWritable)) {
-                    NewOutputPending = TRUE;
-                    XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
-                    XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
-                    if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
-                        AnyWritesPending = FALSE;
-                }
-                if (NumNotifyWriteFd != 0) {
-                    XFD_ANDSET(&tmp_set, &LastSelectWriteMask, &NotifyWriteFds);
-                    if (XFD_ANYSET(&tmp_set))
-                        someNotifyWriteReady = TRUE;
+            for (p = 0; p < poll_fds_num; p++) {
+                short   revents = poll_fds[p].revents;
+
+                if (revents) {
+                    int client_index = ConnectionTranslation[poll_fds[p].fd];
+
+                    if (client_index) {
+                        if (revents & ~(POLLIN|POLLOUT))
+                            CloseDownClient(clients[client_index]);
+                        else {
+                            if (revents & POLLIN) {
+                                mark_client_ready(clients[client_index]);
+                                clients_are_ready = TRUE;
+                            }
+                            if (revents & POLLOUT) {
+                                NewOutputPending = TRUE;
+                            }
+                        }
+                    } else {
+                        HandleNotifyFd(poll_fds[p].fd, revents);
+                    }
                 }
             }
 
-            XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
-
-            XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds);
-            if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady)
-                HandleNotifyFds();
-
-            if (clients_are_ready || XFD_ANYSET(&clientsReadable))
-                break;
-
             /* check here for DDXes that queue events during Block/Wakeup */
             if (*checkForInput[0] != *checkForInput[1])
                 return FALSE;
-        }
-    }
-
-    nready = 0;
-    if (XFD_ANYSET(&clientsReadable)) {
-#ifndef WIN32
-        for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
-            while (clientsReadable.fds_bits[i]) {
-                int client_index;
-
-                curclient = mffs(clientsReadable.fds_bits[i]) - 1;
-                client_index =  /* raphael: modified */
-                    ConnectionTranslation[curclient +
-                                          (i * (sizeof(fd_mask) * 8))];
-#else
-        fd_set savedClientsReadable;
-
-        XFD_COPYSET(&clientsReadable, &savedClientsReadable);
-        for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) {
-            int client_priority, client_index;
 
-            curclient = XFD_FD(&savedClientsReadable, i);
-            client_index = GetConnectionTranslation(curclient);
-#endif
-            nready++;
-            mark_client_ready(clients[client_index]);
-#ifndef WIN32
-            clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
-        }
-#else
-            FD_CLR(curclient, &clientsReadable);
-#endif
+            if (clients_are_ready)
+                break;
         }
     }
 
-    if (nready)
-        SmartScheduleStartTimer();
+    if (clients_are_ready) {
+        clients_were_ready = TRUE;
+        if (!timer_is_running)
+            SmartScheduleStartTimer();
+    }
 
     return TRUE;
 }
diff --git a/os/connection.c b/os/connection.c
index d3fda35..edf1764 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -121,6 +121,9 @@ SOFTWARE.
 
 static int lastfdesc;           /* maximum file descriptor */
 
+struct pollfd   *poll_fds;
+int             poll_fds_num;
+
 fd_set NotifyReadFds;           /* mask for other file descriptors */
 fd_set NotifyWriteFds;          /* mask for other write file descriptors */
 fd_set AllSockets;              /* select on this */
@@ -155,6 +158,12 @@ int GrabInProgress = 0;
 static void
 QueueNewConnections(int curconn, int ready, void *data);
 
+static void
+set_poll_client(ClientPtr client);
+
+static void
+set_poll_clients(void);
+
 #if !defined(WIN32)
 int *ConnectionTranslation = NULL;
 #else
@@ -392,6 +401,7 @@ CreateWellKnownSockets(void)
     int i;
     int partial;
 
+    poll_fd_init();
     FD_ZERO(&AllSockets);
     FD_ZERO(&AllClients);
     FD_ZERO(&LastSelectMask);
@@ -774,6 +784,7 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
     oc->output = (ConnectionOutputPtr) NULL;
     oc->auth_id = None;
     oc->conn_time = conn_time;
+    oc->flags = 0;
     if (!(client = NextAvailableClient((void *) oc))) {
         free(oc);
         return NullClient;
@@ -784,6 +795,9 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
 #else
     SetConnectionTranslation(fd, client->index);
 #endif
+    poll_fd_add(fd);
+    set_poll_client(client);
+
     if (GrabInProgress) {
         FD_SET(fd, &SavedAllClients);
         FD_SET(fd, &SavedAllSockets);
@@ -944,6 +958,7 @@ CloseDownFileDescriptor(OsCommPtr oc)
 #else
     SetConnectionTranslation(connection, 0);
 #endif
+    poll_fd_remove(connection);
     FD_CLR(connection, &AllSockets);
     FD_CLR(connection, &AllClients);
     FD_CLR(connection, &ClientsWithInput);
@@ -1046,22 +1061,6 @@ CloseDownConnection(ClientPtr client)
         AuditF("client %d disconnected\n", client->index);
 }
 
-static void
-AddGeneralSocket(int fd)
-{
-    FD_SET(fd, &AllSockets);
-    if (GrabInProgress)
-        FD_SET(fd, &SavedAllSockets);
-}
-
-static void
-RemoveGeneralSocket(int fd)
-{
-    FD_CLR(fd, &AllSockets);
-    if (GrabInProgress)
-        FD_CLR(fd, &SavedAllSockets);
-}
-
 struct notify_fd {
     struct xorg_list list;
     int fd;
@@ -1118,20 +1117,30 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
 
     if (changes & X_NOTIFY_READ) {
         if (mask & X_NOTIFY_READ) {
+            poll_fd_add(fd);
+            poll_fd_listen(fd, POLLIN);
             FD_SET(fd, &NotifyReadFds);
-            AddGeneralSocket(fd);
+            FD_SET(fd, &AllSockets);
+            if (GrabInProgress)
+                FD_SET(fd, &SavedAllSockets);
         } else {
-            RemoveGeneralSocket(fd);
+            poll_fd_mute(fd, POLLIN);
+            FD_CLR(fd, &AllSockets);
+            if (GrabInProgress)
+                FD_CLR(fd, &SavedAllSockets);
             FD_CLR(fd, &NotifyReadFds);
         }
     }
 
     if (changes & X_NOTIFY_WRITE) {
         if (mask & X_NOTIFY_WRITE) {
+            poll_fd_add(fd);
+            poll_fd_listen(fd, POLLOUT);
             FD_SET(fd, &NotifyWriteFds);
             if (!NumNotifyWriteFd++)
                 AnyWritesPending = TRUE;
         } else {
+            poll_fd_mute(fd, POLLOUT);
             FD_CLR(fd, &NotifyWriteFds);
             if (!--NumNotifyWriteFd)
                 if (!XFD_ANYSET(&ClientsWriteBlocked))
@@ -1140,6 +1149,7 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
     }
 
     if (mask == 0) {
+        poll_fd_remove(fd);
         xorg_list_del(&n->list);
         free(n);
     } else {
@@ -1158,6 +1168,25 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
  *****************/
 
 void
+HandleNotifyFd(int fd, short revents)
+{
+    struct notify_fd *n, *next;
+
+    xorg_list_for_each_entry_safe(n, next, &notify_fds, list) {
+        if (n->fd == fd) {
+            int ready = 0;
+            if (n->mask & X_NOTIFY_READ && (revents & POLLIN))
+                ready |= X_NOTIFY_READ;
+            if (n->mask & X_NOTIFY_WRITE && (revents & POLLOUT))
+                ready |= X_NOTIFY_WRITE;
+            if (ready != 0)
+                n->notify(n->fd, ready, n->data);
+            break;
+        }
+    }
+}
+
+void
 HandleNotifyFds(void)
 {
     struct notify_fd *n, *next;
@@ -1209,7 +1238,9 @@ OnlyListenToOneClient(ClientPtr client)
         FD_SET(connection, &AllClients);
         XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
         GrabInProgress = client->index;
+        set_poll_clients();
     }
+
     return rc;
 }
 
@@ -1226,6 +1257,7 @@ ListenToAllClients(void)
         XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
         XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
         GrabInProgress = 0;
+        set_poll_clients();
     }
 }
 
@@ -1247,6 +1279,10 @@ IgnoreClient(ClientPtr client)
 
     isItTimeToYield = TRUE;
     mark_client_not_ready(client);
+
+    oc->flags |= OS_COMM_IGNORED;
+    set_poll_client(client);
+
     if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
         if (FD_ISSET(connection, &ClientsWithInput))
             FD_SET(connection, &IgnoredClientsWithInput);
@@ -1283,6 +1319,9 @@ AttendClient(ClientPtr client)
     if (client->ignoreCount)
         return;
 
+    oc->flags &= ~OS_COMM_IGNORED;
+    set_poll_client(client);
+
     if (!GrabInProgress || GrabInProgress == client->index ||
         FD_ISSET(connection, &GrabImperviousClients)) {
         FD_SET(connection, &AllClients);
@@ -1309,6 +1348,8 @@ MakeClientGrabImpervious(ClientPtr client)
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
     int connection = oc->fd;
 
+    oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
+
     FD_SET(connection, &GrabImperviousClients);
 
     if (ServerGrabCallback) {
@@ -1328,6 +1369,9 @@ MakeClientGrabPervious(ClientPtr client)
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
     int connection = oc->fd;
 
+    oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
+    set_poll_client(client);
+
     FD_CLR(connection, &GrabImperviousClients);
     if (GrabInProgress && (GrabInProgress != client->index)) {
         if (FD_ISSET(connection, &ClientsWithInput)) {
@@ -1420,3 +1464,137 @@ AddClientOnOpenFD(int fd)
 
     return TRUE;
 }
+
+static int      poll_fds_size;
+
+static inline Bool
+listen_to_client(ClientPtr client)
+{
+    OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+    if (oc->flags & OS_COMM_IGNORED)
+        return FALSE;
+
+    if (!GrabInProgress)
+        return TRUE;
+
+    if (client->index == GrabInProgress)
+        return TRUE;
+
+    if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
+        return TRUE;
+
+    return FALSE;
+}
+
+static void
+set_poll_client(ClientPtr client)
+{
+    OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+    if (listen_to_client(client))
+        poll_fd_listen(oc->fd, POLLIN);
+    else
+        poll_fd_mute(oc->fd, POLLIN);
+}
+
+static void
+set_poll_clients(void)
+{
+    int i;
+
+    for (i = 1; i < currentMaxClients; i++) {
+        ClientPtr client = clients[i];
+        if (client && !client->clientGone)
+            set_poll_client(client);
+    }
+}
+
+static int
+poll_fd_find(int fd)
+{
+	int lo = 0;
+	int hi = poll_fds_num - 1;
+
+	while (lo <= hi) {
+		int m = (lo + hi) >> 1;
+		int t = poll_fds[m].fd;
+
+		if (t < fd)
+			lo = m + 1;
+		else if (t > fd)
+			hi = m - 1;
+		else
+			return m;
+	}
+	return -(lo + 1);
+}
+
+void
+poll_fd_init(void)
+{
+    free(poll_fds);
+    poll_fds = NULL;
+    poll_fds_size = poll_fds_num = 0;
+}
+
+Bool
+poll_fd_add(int fd)
+{
+    int pos = poll_fd_find(fd);
+    if (pos >= 0)
+        return TRUE;
+
+    if (poll_fds_num == poll_fds_size) {
+        struct pollfd   *new_poll_fds;
+        int             new_poll_fds_size = poll_fds_size ? poll_fds_size * 2 : MAXCLIENTS * 2;
+
+        new_poll_fds = realloc(poll_fds, new_poll_fds_size * sizeof (struct pollfd));
+        if (!new_poll_fds)
+            return FALSE;
+        poll_fds = new_poll_fds;
+        poll_fds_size = new_poll_fds_size;
+    }
+    pos = -pos - 1;
+    memmove(&poll_fds[pos + 1], &poll_fds[pos], (poll_fds_num - pos) * sizeof (struct pollfd));
+    poll_fds_num++;
+
+    poll_fds[pos].fd = fd;
+    poll_fds[pos].events = 0;
+    poll_fds[pos].revents = 0;
+    return TRUE;
+}
+
+void
+poll_fd_remove(int fd)
+{
+    int pos = poll_fd_find(fd);
+
+    if (pos < 0)
+        return;
+
+    poll_fds_num--;
+    memmove(&poll_fds[pos], &poll_fds[pos+1], (poll_fds_num - pos) * sizeof (struct pollfd));
+}
+
+void
+poll_fd_listen(int fd, short events)
+{
+    int pos = poll_fd_find(fd);
+
+    if (pos < 0)
+        return;
+
+    poll_fds[pos].events |= events;
+}
+
+void
+poll_fd_mute(int fd, short events)
+{
+    int pos = poll_fd_find(fd);
+
+    if (pos < 0)
+        return;
+
+    poll_fds[pos].events &= ~events;
+}
diff --git a/os/osdep.h b/os/osdep.h
index 3dc2daf..4680850 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -63,6 +63,8 @@ SOFTWARE.
 #undef _POSIX_SOURCE
 #endif
 
+#include <poll.h>
+
 #ifndef OPEN_MAX
 #ifdef SVR4
 #define OPEN_MAX 512
@@ -148,8 +150,12 @@ typedef struct _osComm {
     XID auth_id;                /* authorization id */
     CARD32 conn_time;           /* timestamp if not established, else 0  */
     struct _XtransConnInfo *trans_conn; /* transport connection object */
+    int flags;
 } OsCommRec, *OsCommPtr;
 
+#define OS_COMM_GRAB_IMPERVIOUS 1
+#define OS_COMM_IGNORED         2
+
 extern int FlushClient(ClientPtr /*who */ ,
                        OsCommPtr /*oc */ ,
                        const void * /*extraBuf */ ,
@@ -161,10 +167,16 @@ extern void FreeOsBuffers(OsCommPtr     /*oc */
 
 extern void InitNotifyFds(void);
 
+void
+HandleNotifyFd(int fd, short revents);
+
 extern void HandleNotifyFds(void);
 
 #include "dix.h"
 
+extern struct pollfd   *poll_fds;
+extern int             poll_fds_num;
+
 extern fd_set AllSockets;
 extern fd_set AllClients;
 extern fd_set LastSelectMask;
@@ -178,6 +190,21 @@ extern fd_set ClientsWriteBlocked;
 extern fd_set OutputPending;
 extern fd_set IgnoredClientsWithInput;
 
+void
+poll_fd_init(void);
+
+Bool
+poll_fd_add(int fd);
+
+void
+poll_fd_remove(int fd);
+
+void
+poll_fd_listen(int fd, short events);
+
+void
+poll_fd_mute(int fd, short events);
+
 #if !defined(WIN32) || defined(__CYGWIN__)
 extern int *ConnectionTranslation;
 #else
-- 
2.8.0.rc3



More information about the xorg-devel mailing list