xserver: Branch 'master' - 12 commits

Adam Jackson ajax at kemper.freedesktop.org
Thu Jul 21 19:05:48 UTC 2016


 configure.ac                             |    3 
 dix/dispatch.c                           |  117 +++++---
 hw/dmx/input/lnx-ms.c                    |    4 
 hw/dmx/input/lnx-ps2.c                   |    4 
 hw/kdrive/linux/mouse.c                  |    6 
 hw/kdrive/linux/ms.c                     |    4 
 hw/kdrive/linux/ps2.c                    |    4 
 hw/xfree86/drivers/modesetting/present.c |    4 
 hw/xfree86/drivers/modesetting/vblank.c  |    1 
 hw/xfree86/os-support/shared/posix_tty.c |    8 
 hw/xfree86/os-support/shared/sigio.c     |    4 
 hw/xfree86/os-support/solaris/sun_bell.c |    4 
 include/dix-config.h.in                  |    6 
 include/dixstruct.h                      |   35 ++
 include/misc.h                           |    2 
 include/os.h                             |    5 
 include/xserver_poll.h                   |   55 +++
 os/Makefile.am                           |    8 
 os/WaitFor.c                             |  375 +++++++++-----------------
 os/connection.c                          |  444 +++++++++----------------------
 os/inputthread.c                         |  120 +++++---
 os/io.c                                  |  104 +------
 os/osdep.h                               |   69 +---
 os/osinit.c                              |   15 -
 os/ospoll.c                              |  442 ++++++++++++++++++++++++++++++
 os/ospoll.h                              |  142 +++++++++
 os/utils.c                               |    6 
 os/xdmcp.c                               |    1 
 os/xserver_poll.c                        |  277 +++++++++++++++++++
 29 files changed, 1461 insertions(+), 808 deletions(-)

New commits:
commit 0b2f30834b1a9f4a03542e25c5f54ae800df57e2
Author: Keith Packard <keithp at keithp.com>
Date:   Sun May 29 17:47:29 2016 -0700

    os: Clean up WaitFor.c
    
    Do all timer stuff before blocking, avoiding a bunch of duplicate code
    and merge common code in WaitForSomething.
    
    The WaitForSomething changes need a bit of explanation to show that
    the new code is effectively equivalent to the old. Eliding error
    checking and trivial bits we've got:
    
    Before:
    
    	if (ready clients)
    		timeout = 0
    	else
    		compute timeout
    	i = poll
    	if (i <= 0) {
    		if (ready clients)
    			return TRUE;
    		if (input)
    			return FALSE;
    		if (any ready timers) {
    			run timers
    			return FALSE;
    		}
    	} else {
    		if (input)
    			return FALSE;
    		if (any ready timers) {
    			run timers
    			return FALSE;
    		}
    		if (ready clients)
    			return TRUE;
    	}
    
    After:
    
    	if (ready clients)
    		timeout = 0;
    	else
    		compute timeout
    		run_timers
    	poll
    
    	if (input)
    		return FALSE;
    
    	if (ready clients)
    		return TRUE;
    
    The old code would return TRUE if there were ready clients and input
    pending. Dispatch would then schedule that ready client, but before
    processing any requests, it would notice that there was input pending
    and go process it. The new code just checks for input first, which is
    effectively the same.
    
    If the poll timed out and there weren't clients ready, then timers
    would get run.
    
    If the poll didn't time out, then timers would get run, even if there
    were clients now ready. Now, if the timeout interval was zero, that
    means that the timers must have been ready *before* poll was
    invoked. In this case, we should simply run the timers before calling
    poll -- no sense calling poll just to discard any data that it
    generates.
    
    If the timeout interval was non-zero, and poll didn't timeout, then
    either there aren't any timers to run, or we got a surprise and hit a
    timer exactly as a client became ready to run. This is the one case
    where the new code is different from the old; the new code delays the
    timer call until the next time WaitForSomething is called.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/os/WaitFor.c b/os/WaitFor.c
index 334c3fe..024df35 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -121,6 +121,7 @@ struct _OsTimerRec {
 };
 
 static void DoTimer(OsTimerPtr timer, CARD32 now);
+static void DoTimers(CARD32 now);
 static void CheckAllTimers(void);
 static volatile struct xorg_list timers;
 
@@ -133,6 +134,33 @@ first_timer(void)
     return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
 }
 
+/*
+ * Compute timeout until next timer, running
+ * any expired timers
+ */
+static int
+check_timers(void)
+{
+    OsTimerPtr timer;
+
+    while ((timer = first_timer()) != NULL) {
+        CARD32 now = GetTimeInMillis();
+        int timeout = timer->expires - now;
+
+        if (timeout <= 0) {
+            DoTimers(now);
+        } else {
+            /* Make sure the timeout is sane */
+            if (timeout < timer->delta + 250)
+                return timeout;
+
+            /* time has rewound.  reset the timers. */
+            CheckAllTimers();
+        }
+    }
+    return -1;
+}
+
 /*****************
  * WaitForSomething:
  *     Make the server suspend until there is
@@ -158,8 +186,6 @@ WaitForSomething(Bool are_ready)
     int pollerr;
     static Bool were_ready;
     Bool timer_is_running;
-    CARD32 now = 0;
-    OsTimerPtr timer;
 
     timer_is_running = were_ready;
 
@@ -181,27 +207,10 @@ WaitForSomething(Bool are_ready)
         if (workQueue)
             ProcessWorkQueue();
 
-        if (are_ready) {
+        if (are_ready)
             timeout = 0;
-        }
-        else {
-            timeout = -1;
-            if ((timer = first_timer()) != NULL) {
-                now = GetTimeInMillis();
-                timeout = timer->expires - now;
-                if (timeout > 0 && timeout > timer->delta + 250) {
-                    /* time has rewound.  reset the timers. */
-                    CheckAllTimers();
-                    timer = first_timer();
-                }
-
-                if (timer) {
-                    timeout = timer->expires - now;
-                    if (timeout < 0)
-                        timeout = 0;
-                }
-            }
-        }
+        else
+            timeout = check_timers();
 
         BlockHandler(&timeout);
         if (NewOutputPending)
@@ -217,76 +226,24 @@ WaitForSomething(Bool are_ready)
             if (dispatchException)
                 return FALSE;
             if (i < 0) {
-                if (pollerr == EINVAL) {
-                    FatalError("WaitForSomething(): poll: %s\n",
-                               strerror(pollerr));
-                }
-                else if (pollerr != EINTR && pollerr != EAGAIN) {
+                if (pollerr != EINTR && !ETEST(pollerr)) {
                     ErrorF("WaitForSomething(): poll: %s\n",
                            strerror(pollerr));
                 }
             }
-            else if (are_ready) {
-                /*
-                 * If no-one else is home, bail quickly
-                 */
-                break;
-            }
-            if (*checkForInput[0] != *checkForInput[1])
-                return FALSE;
-
-            if ((timer = first_timer()) != NULL) {
-                int expired = 0;
-
-                now = GetTimeInMillis();
-                if ((int) (timer->expires - now) <= 0)
-                    expired = 1;
-
-                if (expired) {
-                    OsBlockSignals();
-                    while ((timer = first_timer()) != NULL && (int) (timer->expires - now) <= 0)
-                        DoTimer(timer, now);
-                    OsReleaseSignals();
-
-                    return FALSE;
-                }
-            }
-        }
-        else {
-            /* check here for DDXes that queue events during Block/Wakeup */
-            if (*checkForInput[0] != *checkForInput[1])
-                return FALSE;
-
-            if ((timer = first_timer()) != NULL) {
-                int expired = 0;
-
-                now = GetTimeInMillis();
-                if ((int) (timer->expires - now) <= 0)
-                    expired = 1;
-
-                if (expired) {
-                    OsBlockSignals();
-                    while ((timer = first_timer()) != NULL && (int) (timer->expires - now) <= 0)
-                        DoTimer(timer, now);
-                    OsReleaseSignals();
+        } else
+            are_ready = clients_are_ready();
 
-                    return FALSE;
-                }
-            }
+        if (*checkForInput[0] != *checkForInput[1])
+            return FALSE;
 
-            are_ready = clients_are_ready();
-            if (are_ready)
-                break;
+        if (are_ready) {
+            were_ready = TRUE;
+            if (!timer_is_running)
+                SmartScheduleStartTimer();
+            return TRUE;
         }
     }
-
-    if (are_ready) {
-        were_ready = TRUE;
-        if (!timer_is_running)
-            SmartScheduleStartTimer();
-    }
-
-    return TRUE;
 }
 
 void
commit 2ab8b1dcd37900e5e2f11007d7c0cd0545209482
Author: Keith Packard <keithp at keithp.com>
Date:   Sun May 29 19:48:25 2016 -0700

    os: Use xorg_list for struct _OsTimerRec
    
    No sense having an open-coded linked list here, plus the doubly linked
    list is more efficient
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/os/WaitFor.c b/os/WaitFor.c
index a5f5812..334c3fe 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -113,16 +113,25 @@ mffs(fd_mask mask)
 #endif
 
 struct _OsTimerRec {
-    OsTimerPtr next;
+    struct xorg_list list;
     CARD32 expires;
     CARD32 delta;
     OsTimerCallback callback;
     void *arg;
 };
 
-static void DoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev);
+static void DoTimer(OsTimerPtr timer, CARD32 now);
 static void CheckAllTimers(void);
-static volatile OsTimerPtr timers = NULL;
+static volatile struct xorg_list timers;
+
+static inline OsTimerPtr
+first_timer(void)
+{
+    /* inline xorg_list_is_empty which can't handle volatile */
+    if (timers.next == &timers)
+        return NULL;
+    return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
+}
 
 /*****************
  * WaitForSomething:
@@ -150,6 +159,7 @@ WaitForSomething(Bool are_ready)
     static Bool were_ready;
     Bool timer_is_running;
     CARD32 now = 0;
+    OsTimerPtr timer;
 
     timer_is_running = were_ready;
 
@@ -176,16 +186,17 @@ WaitForSomething(Bool are_ready)
         }
         else {
             timeout = -1;
-            if (timers) {
+            if ((timer = first_timer()) != NULL) {
                 now = GetTimeInMillis();
-                timeout = timers->expires - now;
-                if (timeout > 0 && timeout > timers->delta + 250) {
+                timeout = timer->expires - now;
+                if (timeout > 0 && timeout > timer->delta + 250) {
                     /* time has rewound.  reset the timers. */
                     CheckAllTimers();
+                    timer = first_timer();
                 }
 
-                if (timers) {
-                    timeout = timers->expires - now;
+                if (timer) {
+                    timeout = timer->expires - now;
                     if (timeout < 0)
                         timeout = 0;
                 }
@@ -224,17 +235,17 @@ WaitForSomething(Bool are_ready)
             if (*checkForInput[0] != *checkForInput[1])
                 return FALSE;
 
-            if (timers) {
+            if ((timer = first_timer()) != NULL) {
                 int expired = 0;
 
                 now = GetTimeInMillis();
-                if ((int) (timers->expires - now) <= 0)
+                if ((int) (timer->expires - now) <= 0)
                     expired = 1;
 
                 if (expired) {
                     OsBlockSignals();
-                    while (timers && (int) (timers->expires - now) <= 0)
-                        DoTimer(timers, now, &timers);
+                    while ((timer = first_timer()) != NULL && (int) (timer->expires - now) <= 0)
+                        DoTimer(timer, now);
                     OsReleaseSignals();
 
                     return FALSE;
@@ -246,17 +257,17 @@ WaitForSomething(Bool are_ready)
             if (*checkForInput[0] != *checkForInput[1])
                 return FALSE;
 
-            if (timers) {
+            if ((timer = first_timer()) != NULL) {
                 int expired = 0;
 
                 now = GetTimeInMillis();
-                if ((int) (timers->expires - now) <= 0)
+                if ((int) (timer->expires - now) <= 0)
                     expired = 1;
 
                 if (expired) {
                     OsBlockSignals();
-                    while (timers && (int) (timers->expires - now) <= 0)
-                        DoTimer(timers, now, &timers);
+                    while ((timer = first_timer()) != NULL && (int) (timer->expires - now) <= 0)
+                        DoTimer(timer, now);
                     OsReleaseSignals();
 
                     return FALSE;
@@ -288,6 +299,10 @@ AdjustWaitForDelay(void *waitTime, int newdelay)
         *timeoutp = newdelay;
 }
 
+static inline Bool timer_pending(OsTimerPtr timer) {
+    return !xorg_list_is_empty(&timer->list);
+}
+
 /* If time has rewound, re-run every affected timer.
  * Timers might drop out of the list, so we have to restart every time. */
 static void
@@ -300,9 +315,9 @@ CheckAllTimers(void)
  start:
     now = GetTimeInMillis();
 
-    for (timer = timers; timer; timer = timer->next) {
+    xorg_list_for_each_entry(timer, &timers, list) {
         if (timer->expires - now > timer->delta + 250) {
-            TimerForce(timer);
+            DoTimer(timer, now);
             goto start;
         }
     }
@@ -310,41 +325,49 @@ CheckAllTimers(void)
 }
 
 static void
-DoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev)
+DoTimer(OsTimerPtr timer, CARD32 now)
 {
     CARD32 newTime;
 
-    input_lock();
-    *prev = timer->next;
-    timer->next = NULL;
-    input_unlock();
-
+    xorg_list_del(&timer->list);
     newTime = (*timer->callback) (timer, now, timer->arg);
     if (newTime)
         TimerSet(timer, 0, newTime, timer->callback, timer->arg);
 }
 
+static void
+DoTimers(CARD32 now)
+{
+    OsTimerPtr  timer;
+
+    input_lock();
+    while ((timer = first_timer())) {
+        if ((int) (timer->expires - now) > 0)
+            break;
+        DoTimer(timer, now);
+    }
+    input_unlock();
+}
+
 OsTimerPtr
 TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
          OsTimerCallback func, void *arg)
 {
-    volatile OsTimerPtr *prev;
+    OsTimerPtr existing, tmp;
     CARD32 now = GetTimeInMillis();
 
     if (!timer) {
-        timer = malloc(sizeof(struct _OsTimerRec));
+        timer = calloc(1, sizeof(struct _OsTimerRec));
         if (!timer)
             return NULL;
+        xorg_list_init(&timer->list);
     }
     else {
         input_lock();
-        for (prev = &timers; *prev; prev = &(*prev)->next) {
-            if (*prev == timer) {
-                *prev = timer->next;
-                if (flags & TimerForceOld)
-                    (void) (*timer->callback) (timer, now, timer->arg);
-                break;
-            }
+        if (timer_pending(timer)) {
+            xorg_list_del(&timer->list);
+            if (flags & TimerForceOld)
+                (void) (*timer->callback) (timer, now, timer->arg);
         }
         input_unlock();
     }
@@ -360,18 +383,19 @@ TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
     timer->expires = millis;
     timer->callback = func;
     timer->arg = arg;
-    if ((int) (millis - now) <= 0) {
-        timer->next = NULL;
-        millis = (*timer->callback) (timer, now, timer->arg);
-        if (!millis)
-            return timer;
-    }
     input_lock();
-    for (prev = &timers;
-         *prev && (int) ((*prev)->expires - millis) <= 0;
-         prev = &(*prev)->next);
-    timer->next = *prev;
-    *prev = timer;
+
+    /* Sort into list */
+    xorg_list_for_each_entry_safe(existing, tmp, &timers, list)
+        if ((int) (existing->expires - millis) > 0)
+            break;
+    /* This even works at the end of the list -- existing->list will be timers */
+    xorg_list_add(&timer->list, existing->list.prev);
+
+    /* Check to see if the timer is ready to run now */
+    if ((int) (millis - now) <= 0)
+        DoTimer(timer, now);
+
     input_unlock();
     return timer;
 }
@@ -379,35 +403,23 @@ TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
 Bool
 TimerForce(OsTimerPtr timer)
 {
-    int rc = FALSE;
-    volatile OsTimerPtr *prev;
+    int pending;
 
     input_lock();
-    for (prev = &timers; *prev; prev = &(*prev)->next) {
-        if (*prev == timer) {
-            DoTimer(timer, GetTimeInMillis(), prev);
-            rc = TRUE;
-            break;
-        }
-    }
+    pending = timer_pending(timer);
+    if (pending)
+        DoTimer(timer, GetTimeInMillis());
     input_unlock();
-    return rc;
+    return pending;
 }
 
 void
 TimerCancel(OsTimerPtr timer)
 {
-    volatile OsTimerPtr *prev;
-
     if (!timer)
         return;
     input_lock();
-    for (prev = &timers; *prev; prev = &(*prev)->next) {
-        if (*prev == timer) {
-            *prev = timer->next;
-            break;
-        }
-    }
+    xorg_list_del(&timer->list);
     input_unlock();
 }
 
@@ -423,23 +435,22 @@ TimerFree(OsTimerPtr timer)
 void
 TimerCheck(void)
 {
-    CARD32 now = GetTimeInMillis();
-
-    if (timers && (int) (timers->expires - now) <= 0) {
-        input_lock();
-        while (timers && (int) (timers->expires - now) <= 0)
-            DoTimer(timers, now, &timers);
-        input_unlock();
-    }
+    DoTimers(GetTimeInMillis());
 }
 
 void
 TimerInit(void)
 {
-    OsTimerPtr timer;
+    static Bool been_here;
+    OsTimerPtr timer, tmp;
+
+    if (!been_here) {
+        been_here = TRUE;
+        xorg_list_init((struct xorg_list*) &timers);
+    }
 
-    while ((timer = timers)) {
-        timers = timer->next;
+    xorg_list_for_each_entry_safe(timer, tmp, &timers, list) {
+        xorg_list_del(&timer->list);
         free(timer);
     }
 }
commit 50779c494d4682103b96db440021e56e44311b6b
Author: Keith Packard <keithp at keithp.com>
Date:   Sun May 29 12:45:53 2016 -0700

    os: Remove CheckConnections
    
    poll provides per-fd notification of failure, so we don't need
    CheckConnections anymore.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/include/os.h b/include/os.h
index 765562c..d2c41b4 100644
--- a/include/os.h
+++ b/include/os.h
@@ -141,8 +141,6 @@ extern _X_EXPORT const char *ClientAuthorized(ClientPtr /*client */ ,
                                               unsigned int /*string_n */ ,
                                               char * /*auth_string */ );
 
-extern _X_EXPORT void CheckConnections(void);
-
 extern _X_EXPORT void CloseDownConnection(ClientPtr /*client */ );
 
 typedef void (*NotifyFdProcPtr)(int fd, int ready, void *data);
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 87f8abd..a5f5812 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -206,11 +206,7 @@ WaitForSomething(Bool are_ready)
             if (dispatchException)
                 return FALSE;
             if (i < 0) {
-                if (pollerr == EBADF) {       /* Some client disconnected */
-                    CheckConnections();
-                    return FALSE;
-                }
-                else if (pollerr == EINVAL) {
+                if (pollerr == EINVAL) {
                     FatalError("WaitForSomething(): poll: %s\n",
                                strerror(pollerr));
                 }
diff --git a/os/connection.c b/os/connection.c
index 26829ec..4294ee7 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -47,7 +47,7 @@ SOFTWARE.
  *  Stuff to create connections --- OS dependent
  *
  *      EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
- *      CloseDownConnection, CheckConnections
+ *      CloseDownConnection,
  *	OnlyListToOneClient,
  *      ListenToAllClients,
  *
@@ -78,7 +78,6 @@ SOFTWARE.
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <poll.h>
 
 #ifndef WIN32
 #include <sys/socket.h>
@@ -899,39 +898,6 @@ CloseDownFileDescriptor(OsCommPtr oc)
 }
 
 /*****************
- * CheckConnections
- *    Some connection has died, go find which one and shut it down
- *    The file descriptor has been closed, but is still in AllClients.
- *    If would truly be wonderful if select() would put the bogus
- *    file descriptors in the exception mask, but nooooo.  So we have
- *    to check each and every socket individually.
- *****************/
-
-void
-CheckConnections(void)
-{
-    int i;
-    int r;
-
-    for (i = 1; i < currentMaxClients; i++) {
-        ClientPtr client = clients[i];
-        if (!client->clientGone) {
-            OsCommPtr           oc = (OsCommPtr) client->osPrivate;
-            struct pollfd       poll_fd;
-
-            poll_fd.fd = oc->fd;
-            poll_fd.events = POLLIN|POLLOUT;
-
-            do {
-                r = poll(&poll_fd, 1, 0);
-            } while (r < 0 && (errno == EINTR || errno == EAGAIN));
-            if (r < 0)
-                CloseDownClient(client);
-        }
-    }
-}
-
-/*****************
  * CloseDownConnection
  *    Delete client from AllClients and free resources
  *****************/
commit f0275b1e5a4787da1f4d5507165315a000c22b33
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 26 00:19:55 2016 -0700

    os: Leave stdin and stdout open
    
    There's no reason to close these now that we don't care what file
    descriptors we use.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/os/osinit.c b/os/osinit.c
index ab9c1d6..47061bb 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -224,17 +224,6 @@ OsInit(void)
 #endif
 
 #if !defined(XQUARTZ)    /* STDIN is already /dev/null and STDOUT/STDERR is managed by console_redirect.c */
-# if defined(__APPLE__)
-        int devnullfd = open(devnull, O_RDWR, 0);
-        assert(devnullfd > 2);
-
-        dup2(devnullfd, STDIN_FILENO);
-        dup2(devnullfd, STDOUT_FILENO);
-        close(devnullfd);
-# elif !defined(__CYGWIN__)
-        fclose(stdin);
-        fclose(stdout);
-# endif
         /*
          * If a write of zero bytes to stderr returns non-zero, i.e. -1,
          * then writing to stderr failed, and we'll write somewhere else
commit 8217c29d2d8b29bd66bc54fee3fe5cb3385a05c7
Author: Keith Packard <keithp at keithp.com>
Date:   Wed May 25 23:43:49 2016 -0700

    Allow 1024 and 2048 for LimitClients
    
    There's no reason not to offer ridiculous numbers of clients; only a
    few static data structures are arrays of this length.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/include/misc.h b/include/misc.h
index 006f768..01747fd 100644
--- a/include/misc.h
+++ b/include/misc.h
@@ -87,7 +87,7 @@ OF THIS SOFTWARE.
 #ifndef MAXGPUSCREENS
 #define MAXGPUSCREENS	16
 #endif
-#define MAXCLIENTS	512
+#define MAXCLIENTS	2048
 #define LIMITCLIENTS	256     /* Must be a power of 2 and <= MAXCLIENTS */
 #define MAXEXTENSIONS   128
 #define MAXFORMATS	8
diff --git a/os/utils.c b/os/utils.c
index 868a2d6..ac55cd7 100644
--- a/os/utils.c
+++ b/os/utils.c
@@ -867,8 +867,10 @@ ProcessCommandLine(int argc, char *argv[])
 		if (LimitClients != 64 &&
 		    LimitClients != 128 &&
 		    LimitClients != 256 &&
-		    LimitClients != 512) {
-		    FatalError("maxclients must be one of 64, 128, 256 or 512\n");
+		    LimitClients != 512 &&
+                    LimitClients != 1024 &&
+                    LimitClients != 2048) {
+		    FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n");
 		}
 	    } else
 		UseMsg();
commit e0edb963fe09582f23a4b55da4f8840173e7a1ee
Author: Keith Packard <keithp at keithp.com>
Date:   Tue May 24 21:04:14 2016 -0700

    os: eliminate fd value limits for clients
    
    With no code depending on the range of file descriptors, checking
    for that can be eliminated.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/os/connection.c b/os/connection.c
index 8c7f713..26829ec 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -104,7 +104,6 @@ SOFTWARE.
 #endif                          /* WIN32 */
 #include "misc.h"               /* for typedef of pointer */
 #include "osdep.h"
-#include <X11/Xpoll.h>
 #include "opaque.h"
 #include "dixstruct.h"
 #include "xace.h"
@@ -120,7 +119,6 @@ SOFTWARE.
 
 #include "probes.h"
 
-static int lastfdesc;           /* maximum file descriptor */
 struct ospoll   *server_poll;
 
 int MaxClients = 0;
@@ -134,8 +132,6 @@ static char dynamic_display[7]; /* display name */
 Bool PartialNetwork;            /* continue even if unable to bind all addrs */
 static Pid_t ParentProcess;
 
-static Bool debug_conns = FALSE;
-
 int GrabInProgress = 0;
 
 static void
@@ -149,19 +145,15 @@ set_poll_clients(void);
 
 #if !defined(WIN32)
 int *ConnectionTranslation = NULL;
+int ConnectionTranslationSize = 0;
 #else
 /*
- * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
+ * On NT fds are not small integers, they are unrelated, and there is
  * not even a known maximum value, so use something quite arbitrary for now.
  * Do storage is a hash table of size 256. Collisions are handled in a linked
  * list.
  */
 
-#undef MAXSOCKS
-#define MAXSOCKS 512
-#undef MAXSELECT
-#define MAXSELECT 512
-
 struct _ct_node {
     struct _ct_node *next;
     int key;
@@ -266,47 +258,17 @@ lookup_trans_conn(int fd)
 void
 InitConnectionLimits(void)
 {
-    lastfdesc = -1;
-
-#ifndef __CYGWIN__
-
-#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
-    lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
-#endif
-
-#ifdef HAVE_GETDTABLESIZE
-    if (lastfdesc < 0)
-        lastfdesc = getdtablesize() - 1;
-#endif
-
-#ifdef _NFILE
-    if (lastfdesc < 0)
-        lastfdesc = _NFILE - 1;
-#endif
-
-#endif                          /* __CYGWIN__ */
-
-    /* This is the fallback */
-    if (lastfdesc < 0)
-        lastfdesc = MAXSOCKS;
-
-    if (lastfdesc > MAXSELECT)
-        lastfdesc = MAXSELECT;
-
-    if (lastfdesc > MAXCLIENTS) {
-        lastfdesc = MAXCLIENTS;
-        if (debug_conns)
-            ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", LimitClients);
-    }
-    MaxClients = lastfdesc;
+    MaxClients = MAXCLIENTS;
 
 #ifdef DEBUG
     ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
 #endif
 
 #if !defined(WIN32)
-    if (!ConnectionTranslation)
-        ConnectionTranslation = xnfallocarray(lastfdesc + 1, sizeof(int));
+    if (!ConnectionTranslation) {
+        ConnectionTranslation = xnfallocarray(MaxClients, sizeof(int));
+        ConnectionTranslationSize = MaxClients;
+    }
 #else
     InitConnectionTranslation();
 #endif
@@ -385,7 +347,7 @@ CreateWellKnownSockets(void)
     int partial;
 
 #if !defined(WIN32)
-    for (i = 0; i < MaxClients; i++)
+    for (i = 0; i < ConnectionTranslationSize; i++)
         ConnectionTranslation[i] = 0;
 #else
     ClearConnectionTranslation();
@@ -761,14 +723,6 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
     OsCommPtr oc;
     ClientPtr client;
 
-    if (
-#ifndef WIN32
-           fd >= lastfdesc
-#else
-           XFD_SETCOUNT(&AllClients) >= MaxClients
-#endif
-        )
-        return NullClient;
     oc = malloc(sizeof(OsCommRec));
     if (!oc)
         return NullClient;
@@ -785,6 +739,10 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
     }
     client->local = ComputeLocalClient(client);
 #if !defined(WIN32)
+    if (fd >= ConnectionTranslationSize) {
+        ConnectionTranslationSize *= 2;
+        ConnectionTranslation = xnfreallocarray(ConnectionTranslation, ConnectionTranslationSize, sizeof (int));
+    }
     ConnectionTranslation[fd] = client->index;
 #else
     SetConnectionTranslation(fd, client->index);
@@ -824,6 +782,7 @@ EstablishNewConnections(ClientPtr clientUnused, void *closure)
     OsCommPtr oc;
     XtransConnInfo trans_conn, new_trans_conn;
     int status;
+    int clientid;
 
     connect_time = GetTimeInMillis();
     /* kill off stragglers */
@@ -845,17 +804,9 @@ EstablishNewConnections(ClientPtr clientUnused, void *closure)
 
     newconn = _XSERVTransGetConnectionNumber(new_trans_conn);
 
-    if (newconn < lastfdesc) {
-        int clientid;
-
-#if !defined(WIN32)
-        clientid = ConnectionTranslation[newconn];
-#else
-        clientid = GetConnectionTranslation(newconn);
-#endif
-        if (clientid && (client = clients[clientid]))
-            CloseDownClient(client);
-    }
+    clientid = GetConnectionTranslation(newconn);
+    if (clientid && (client = clients[clientid]))
+        CloseDownClient(client);
 
     _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
 
diff --git a/os/osdep.h b/os/osdep.h
index df0abeb..90a247f 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -63,42 +63,8 @@ SOFTWARE.
 #undef _POSIX_SOURCE
 #endif
 
-#ifndef OPEN_MAX
-#ifdef SVR4
-#define OPEN_MAX 512
-#else
-#include <sys/param.h>
-#ifndef OPEN_MAX
-#if defined(NOFILE) && !defined(NOFILES_MAX)
-#define OPEN_MAX NOFILE
-#else
-#if !defined(WIN32) || defined(__CYGWIN__)
-#define OPEN_MAX NOFILES_MAX
-#else
-#define OPEN_MAX 512
-#endif
-#endif
-#endif
-#endif
-#endif
-
-#include <X11/Xpoll.h>
-
-/*
- * MAXSOCKS is used only for initialising MaxClients when no other method
- * like sysconf(_SC_OPEN_MAX) is not supported.
- */
-
-#if OPEN_MAX <= 512
-#define MAXSOCKS (OPEN_MAX - 1)
-#else
-#define MAXSOCKS 512
-#endif
-
-/* MAXSELECT is the number of fds that select() can handle */
-#define MAXSELECT (sizeof(fd_set) * NBBY)
-
 #include <stddef.h>
+#include <X11/Xos.h>
 
 /* If EAGAIN and EWOULDBLOCK are distinct errno values, then we check errno
  * for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
@@ -187,6 +153,12 @@ listen_to_client(ClientPtr client);
 
 #if !defined(WIN32) || defined(__CYGWIN__)
 extern int *ConnectionTranslation;
+extern int ConnectionTranslationSize;
+static inline int GetConnectionTranslation(int conn) {
+    if (conn >= ConnectionTranslationSize)
+        return 0;
+    return ConnectionTranslation[conn];
+}
 #else
 extern int GetConnectionTranslation(int conn);
 extern void SetConnectionTranslation(int conn, int client);
commit 30bc0732f959bbc63f318c06d48de080d495da32
Author: Keith Packard <keithp at keithp.com>
Date:   Tue May 24 21:12:33 2016 -0700

    os: Use ospoll for input thread [v2]
    
    Replace use of select(2) to avoid fd limits. Note that
    InputThreadFillPipe used select as well, but none of the files passed
    were non-blocking, so there was no need for that code at all.
    
    v2: Keep ospoll API usage single threaded to avoid re-entrancy issues
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/os/inputthread.c b/os/inputthread.c
index a4266e9..e815319 100644
--- a/os/inputthread.c
+++ b/os/inputthread.c
@@ -35,7 +35,6 @@
 #include <unistd.h>
 #include <pthread.h>
 
-#include <X11/Xpoll.h>
 #include "inputstr.h"
 #include "opaque.h"
 #include "osdep.h"
@@ -47,11 +46,19 @@ Bool InputThreadEnable = TRUE;
 /**
  * An input device as seen by the threaded input facility
  */
+
+typedef enum _InputDeviceState {
+    device_state_added,
+    device_state_running,
+    device_state_removed
+} InputDeviceState;
+
 typedef struct _InputThreadDevice {
     struct xorg_list node;
     NotifyFdProcPtr readInputProc;
     void *readInputArgs;
     int fd;
+    InputDeviceState state;
 } InputThreadDevice;
 
 /**
@@ -62,9 +69,11 @@ typedef struct _InputThreadDevice {
 typedef struct {
     pthread_t thread;
     struct xorg_list devs;
-    fd_set fds;
+    struct ospoll *fds;
     int readPipe;
     int writePipe;
+    Bool changed;
+    Bool running;
 } InputThreadInfo;
 
 static InputThreadInfo *inputThreadInfo;
@@ -154,6 +163,17 @@ InputThreadReadPipe(int readHead)
     return 1;
 }
 
+static void
+InputReady(int fd, int xevents, void *data)
+{
+    InputThreadDevice *dev = data;
+
+    input_lock();
+    if (dev->state == device_state_running)
+        dev->readInputProc(fd, xevents, dev->readInputArgs);
+    input_unlock();
+}
+
 /**
  * Register an input device in the threaded input facility
  *
@@ -182,16 +202,18 @@ InputThreadRegisterDev(int fd,
     dev->fd = fd;
     dev->readInputProc = readInputProc;
     dev->readInputArgs = readInputArgs;
+    dev->state = device_state_added;
 
     input_lock();
     xorg_list_add(&dev->node, &inputThreadInfo->devs);
 
-    FD_SET(fd, &inputThreadInfo->fds);
+    inputThreadInfo->changed = TRUE;
 
-    InputThreadFillPipe(hotplugPipeWrite);
-    DebugF("input-thread: registered device %d\n", fd);
     input_unlock();
 
+    DebugF("input-thread: registered device %d\n", fd);
+    InputThreadFillPipe(hotplugPipeWrite);
+
     return 1;
 }
 
@@ -229,20 +251,26 @@ InputThreadUnregisterDev(int fd)
         return 0;
     }
 
-    xorg_list_del(&dev->node);
-
-    FD_CLR(fd, &inputThreadInfo->fds);
+    dev->state = device_state_removed;
+    inputThreadInfo->changed = TRUE;
 
     input_unlock();
 
-    free(dev);
-
     InputThreadFillPipe(hotplugPipeWrite);
     DebugF("input-thread: unregistered device: %d\n", fd);
 
     return 1;
 }
 
+static void
+InputThreadPipeNotify(int fd, int revents, void *data)
+{
+    /* Empty pending input, shut down if the pipe has been closed */
+    if (InputThreadReadPipe(hotplugPipeRead) == 0) {
+        inputThreadInfo->running = FALSE;
+    }
+}
+
 /**
  * The workhorse of threaded input event generation.
  *
@@ -260,51 +288,66 @@ InputThreadUnregisterDev(int fd)
 static void*
 InputThreadDoWork(void *arg)
 {
-    fd_set readyFds;
-    InputThreadDevice *dev, *next;
     sigset_t set;
 
     /* Don't handle any signals on this thread */
     sigfillset(&set);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
 
-    FD_ZERO(&readyFds);
+    inputThreadInfo->running = TRUE;
 
-    while (1)
-    {
-        XFD_COPYSET(&inputThreadInfo->fds, &readyFds);
-        FD_SET(hotplugPipeRead, &readyFds);
+    ospoll_add(inputThreadInfo->fds, hotplugPipeRead,
+               ospoll_trigger_level,
+               InputThreadPipeNotify,
+               NULL);
+    ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ);
 
+    while (inputThreadInfo->running)
+    {
         DebugF("input-thread: %s waiting for devices\n", __func__);
 
-        if (Select(MAXSELECT, &readyFds, NULL, NULL, NULL) < 0) {
+        /* Check for hotplug changes and modify the ospoll structure to suit */
+        if (inputThreadInfo->changed) {
+            InputThreadDevice *dev, *tmp;
+
+            input_lock();
+            inputThreadInfo->changed = FALSE;
+            xorg_list_for_each_entry_safe(dev, tmp, &inputThreadInfo->devs, node) {
+                switch (dev->state) {
+                case device_state_added:
+                    ospoll_add(inputThreadInfo->fds, dev->fd,
+                               ospoll_trigger_level,
+                               InputReady,
+                               dev);
+                    ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ);
+                    dev->state = device_state_running;
+                    break;
+                case device_state_running:
+                    break;
+                case device_state_removed:
+                    ospoll_remove(inputThreadInfo->fds, dev->fd);
+                    xorg_list_del(&dev->node);
+                    free(dev);
+                    break;
+                }
+            }
+            input_unlock();
+        }
+
+        if (ospoll_wait(inputThreadInfo->fds, -1) < 0) {
             if (errno == EINVAL)
                 FatalError("input-thread: %s (%s)", __func__, strerror(errno));
             else if (errno != EINTR)
                 ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno));
         }
 
-        DebugF("input-thread: %s generating events\n", __func__);
-
-        input_lock();
-        /* Call the device drivers to generate input events for us */
-        xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) {
-            if (FD_ISSET(dev->fd, &readyFds) && dev->readInputProc) {
-                dev->readInputProc(dev->fd, X_NOTIFY_READ, dev->readInputArgs);
-            }
-        }
-        input_unlock();
-
         /* Kick main thread to process the generated input events and drain
          * events from hotplug pipe */
         InputThreadFillPipe(inputThreadInfo->writePipe);
-
-        /* Empty pending input, shut down if the pipe has been closed */
-        if (FD_ISSET(hotplugPipeRead, &readyFds)) {
-            if (InputThreadReadPipe(hotplugPipeRead) == 0)
-                break;
-        }
     }
+
+    ospoll_remove(inputThreadInfo->fds, hotplugPipeRead);
+
     return NULL;
 }
 
@@ -338,7 +381,7 @@ InputThreadPreInit(void)
 
     inputThreadInfo->thread = 0;
     xorg_list_init(&inputThreadInfo->devs);
-    FD_ZERO(&inputThreadInfo->fds);
+    inputThreadInfo->fds = ospoll_create();
 
     /* By making read head non-blocking, we ensure that while the main thread
      * is busy servicing client requests, the dedicated input thread can work
@@ -353,6 +396,7 @@ InputThreadPreInit(void)
     hotplugPipeRead = hotplugPipe[0];
     fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC);
     hotplugPipeWrite = hotplugPipe[1];
+
 }
 
 /**
@@ -407,11 +451,11 @@ InputThreadFini(void)
     pthread_join(inputThreadInfo->thread, NULL);
 
     xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) {
-        FD_CLR(dev->fd, &inputThreadInfo->fds);
+        ospoll_remove(inputThreadInfo->fds, dev->fd);
         free(dev);
     }
     xorg_list_init(&inputThreadInfo->devs);
-    FD_ZERO(&inputThreadInfo->fds);
+    ospoll_destroy(inputThreadInfo->fds);
 
     RemoveNotifyFd(inputThreadInfo->readPipe);
     close(inputThreadInfo->readPipe);
commit f993091e7db81b0420e23c485378cba112278839
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 26 10:40:44 2016 -0700

    os: Switch server to poll(2) [v3]
    
    Eliminates all of the fd_set mangling in the server main thread
    
    v2: Listen for POLLOUT while writes are blocked.
    
    v3: Only mark client not ready on EAGAIN return from read
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 3b9600e..a3c2fbb 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -242,12 +242,14 @@ void Dispatch(void);
 
 static struct xorg_list ready_clients;
 static struct xorg_list saved_ready_clients;
+struct xorg_list output_pending_clients;
 
 static void
 init_client_ready(void)
 {
     xorg_list_init(&ready_clients);
     xorg_list_init(&saved_ready_clients);
+    xorg_list_init(&output_pending_clients);
 }
 
 Bool
@@ -3411,6 +3413,7 @@ CloseDownClient(ClientPtr client)
             UngrabServer(client);
         }
         mark_client_not_ready(client);
+        xorg_list_del(&client->output_pending);
         BITCLEAR(grabWaiters, client->index);
         DeleteClientFromAnySelections(client);
         ReleaseActiveGrabs(client);
@@ -3501,6 +3504,7 @@ InitClient(ClientPtr client, int i, void *ospriv)
 {
     client->index = i;
     xorg_list_init(&client->ready);
+    xorg_list_init(&client->output_pending);
     client->clientAsMask = ((Mask) i) << CLIENTOFFSET;
     client->closeDownMode = i ? DestroyAll : RetainPermanent;
     client->requestVector = InitialVector;
diff --git a/include/dixstruct.h b/include/dixstruct.h
index 1f38349..3b578f8 100644
--- a/include/dixstruct.h
+++ b/include/dixstruct.h
@@ -77,6 +77,7 @@ typedef struct _Client {
     void *requestBuffer;
     void *osPrivate;             /* for OS layer, including scheduler */
     struct xorg_list ready;      /* List of clients ready to run */
+    struct xorg_list output_pending; /* List of clients with output queued */
     Mask clientAsMask;
     short index;
     unsigned char majorOp, minorOp;
@@ -153,6 +154,25 @@ static inline Bool client_is_ready(ClientPtr client)
 Bool
 clients_are_ready(void);
 
+extern struct xorg_list output_pending_clients;
+
+static inline void
+output_pending_mark(ClientPtr client)
+{
+    if (xorg_list_is_empty(&client->output_pending))
+        xorg_list_append(&client->output_pending, &output_pending_clients);
+}
+
+static inline void
+output_pending_clear(ClientPtr client)
+{
+    xorg_list_del(&client->output_pending);
+}
+
+static inline Bool any_output_pending(void) {
+    return !xorg_list_is_empty(&output_pending_clients);
+}
+
 #define SMART_MAX_PRIORITY  (20)
 #define SMART_MIN_PRIORITY  (-20)
 
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 8164c30..87f8abd 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -66,7 +66,6 @@ SOFTWARE.
 #include "misc.h"
 
 #include "osdep.h"
-#include <X11/Xpoll.h>
 #include "dixstruct.h"
 #include "opaque.h"
 #ifdef DPMSExtension
@@ -146,22 +145,20 @@ Bool
 WaitForSomething(Bool are_ready)
 {
     int i;
-    struct timeval waittime, *wt;
     int timeout;
-    fd_set clientsReadable;
-    fd_set clientsWritable;
-    int curclient;
-    int selecterr;
-    static int nready;
+    int pollerr;
+    static Bool were_ready;
+    Bool timer_is_running;
     CARD32 now = 0;
-    Bool someNotifyWriteReady = FALSE;
 
-    FD_ZERO(&clientsReadable);
-    FD_ZERO(&clientsWritable);
+    timer_is_running = were_ready;
 
-    if (nready)
+    if (were_ready && !are_ready) {
+        timer_is_running = FALSE;
         SmartScheduleStopTimer();
-    nready = 0;
+    }
+
+    were_ready = FALSE;
 
 #ifdef BUSFAULT
     busfault_check();
@@ -176,8 +173,6 @@ WaitForSomething(Bool are_ready)
 
         if (are_ready) {
             timeout = 0;
-            XFD_COPYSET(&AllSockets, &LastSelectMask);
-            XFD_UNSET(&LastSelectMask, &ClientsWithInput);
         }
         else {
             timeout = -1;
@@ -195,57 +190,39 @@ WaitForSomething(Bool are_ready)
                         timeout = 0;
                 }
             }
-            XFD_COPYSET(&AllSockets, &LastSelectMask);
         }
 
         BlockHandler(&timeout);
-        if (timeout < 0)
-            wt = NULL;
-        else {
-            waittime.tv_sec = timeout / MILLI_PER_SECOND;
-            waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
-                (1000000 / MILLI_PER_SECOND);
-            wt = &waittime;
-        }
         if (NewOutputPending)
             FlushAllOutput();
         /* 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);
-        }
-        selecterr = GetErrno();
+        else
+            i = ospoll_wait(server_poll, timeout);
+        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 (are_ready) {
                 /*
                  * If no-one else is home, bail quickly
                  */
-                XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
-                XFD_COPYSET(&ClientsWithInput, &clientsReadable);
                 break;
             }
             if (*checkForInput[0] != *checkForInput[1])
@@ -269,93 +246,39 @@ WaitForSomething(Bool are_ready)
             }
         }
         else {
-            fd_set tmp_set;
-
-            if (*checkForInput[0] == *checkForInput[1]) {
-                if (timers) {
-                    int expired = 0;
+            /* check here for DDXes that queue events during Block/Wakeup */
+            if (*checkForInput[0] != *checkForInput[1])
+                return FALSE;
 
-                    now = GetTimeInMillis();
-                    if ((int) (timers->expires - now) <= 0)
-                        expired = 1;
+            if (timers) {
+                int expired = 0;
 
-                    if (expired) {
-                        OsBlockSignals();
-                        while (timers && (int) (timers->expires - now) <= 0)
-                            DoTimer(timers, now, &timers);
-                        OsReleaseSignals();
+                now = GetTimeInMillis();
+                if ((int) (timers->expires - now) <= 0)
+                    expired = 1;
 
-                        return FALSE;
-                    }
-                }
-            }
+                if (expired) {
+                    OsBlockSignals();
+                    while (timers && (int) (timers->expires - now) <= 0)
+                        DoTimer(timers, now, &timers);
+                    OsReleaseSignals();
 
-            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;
+                    return FALSE;
                 }
             }
 
-            XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
-
-            XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds);
-            if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady)
-                HandleNotifyFds();
-
-            if (are_ready || XFD_ANYSET(&clientsReadable))
+            are_ready = clients_are_ready();
+            if (are_ready)
                 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 (are_ready) {
+        were_ready = TRUE;
+        if (!timer_is_running)
+            SmartScheduleStartTimer();
     }
 
-    if (nready)
-        SmartScheduleStartTimer();
-
     return TRUE;
 }
 
diff --git a/os/connection.c b/os/connection.c
index 9e0c976..8c7f713 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -78,6 +78,7 @@ SOFTWARE.
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <poll.h>
 
 #ifndef WIN32
 #include <sys/socket.h>
@@ -120,20 +121,10 @@ SOFTWARE.
 #include "probes.h"
 
 static int lastfdesc;           /* maximum file descriptor */
+struct ospoll   *server_poll;
 
-fd_set NotifyReadFds;           /* mask for other file descriptors */
-fd_set NotifyWriteFds;          /* mask for other write file descriptors */
-fd_set AllSockets;              /* select on this */
-fd_set AllClients;              /* available clients */
-fd_set LastSelectMask;          /* mask returned from last select call */
-fd_set LastSelectWriteMask;     /* mask returned from last select call */
-fd_set ClientsWithInput;        /* clients with FULL requests in buffer */
-fd_set ClientsWriteBlocked;     /* clients who cannot receive output */
-fd_set OutputPending;           /* clients with reply/event data ready to go */
 int MaxClients = 0;
-int NumNotifyWriteFd;           /* Number of NotifyFd members with write set */
 Bool NewOutputPending;          /* not yet attempted to write some new output */
-Bool AnyWritesPending;          /* true if some client blocked on write or NotifyFd with write */
 Bool NoListenAll;               /* Don't establish any listening sockets */
 
 static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
@@ -145,16 +136,17 @@ static Pid_t ParentProcess;
 
 static Bool debug_conns = FALSE;
 
-fd_set IgnoredClientsWithInput;
-static fd_set GrabImperviousClients;
-static fd_set SavedAllClients;
-static fd_set SavedAllSockets;
-static fd_set SavedClientsWithInput;
 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,11 +384,6 @@ CreateWellKnownSockets(void)
     int i;
     int partial;
 
-    FD_ZERO(&AllSockets);
-    FD_ZERO(&AllClients);
-    FD_ZERO(&LastSelectMask);
-    FD_ZERO(&ClientsWithInput);
-
 #if !defined(WIN32)
     for (i = 0; i < MaxClients; i++)
         ConnectionTranslation[i] = 0;
@@ -751,6 +738,23 @@ ClientAuthorized(ClientPtr client,
     return ((char *) NULL);
 }
 
+static void
+ClientReady(int fd, int xevents, void *data)
+{
+    ClientPtr client = data;
+
+    if (xevents & X_NOTIFY_ERROR) {
+        CloseDownClient(client);
+        return;
+    }
+    if (xevents & X_NOTIFY_READ)
+        mark_client_ready(client);
+    if (xevents & X_NOTIFY_WRITE) {
+        ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
+        NewOutputPending = TRUE;
+    }
+}
+
 static ClientPtr
 AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
 {
@@ -774,6 +778,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,14 +789,11 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
 #else
     SetConnectionTranslation(fd, client->index);
 #endif
-    if (GrabInProgress) {
-        FD_SET(fd, &SavedAllClients);
-        FD_SET(fd, &SavedAllSockets);
-    }
-    else {
-        FD_SET(fd, &AllClients);
-        FD_SET(fd, &AllSockets);
-    }
+    ospoll_add(server_poll, fd,
+               ospoll_trigger_edge,
+               ClientReady,
+               client);
+    set_poll_client(client);
 
 #ifdef DEBUG
     ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
@@ -942,19 +944,7 @@ CloseDownFileDescriptor(OsCommPtr oc)
 #else
     SetConnectionTranslation(connection, 0);
 #endif
-    FD_CLR(connection, &AllSockets);
-    FD_CLR(connection, &AllClients);
-    FD_CLR(connection, &ClientsWithInput);
-    FD_CLR(connection, &GrabImperviousClients);
-    if (GrabInProgress) {
-        FD_CLR(connection, &SavedAllSockets);
-        FD_CLR(connection, &SavedAllClients);
-        FD_CLR(connection, &SavedClientsWithInput);
-    }
-    FD_CLR(connection, &ClientsWriteBlocked);
-    if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
-        AnyWritesPending = FALSE;
-    FD_CLR(connection, &OutputPending);
+    ospoll_remove(server_poll, connection);
 }
 
 /*****************
@@ -969,53 +959,25 @@ CloseDownFileDescriptor(OsCommPtr oc)
 void
 CheckConnections(void)
 {
-#ifndef WIN32
-    fd_mask mask;
-#endif
-    fd_set tmask;
-    int curclient, curoff;
     int i;
-    struct timeval notime;
     int r;
 
-#ifdef WIN32
-    fd_set savedAllClients;
-#endif
+    for (i = 1; i < currentMaxClients; i++) {
+        ClientPtr client = clients[i];
+        if (!client->clientGone) {
+            OsCommPtr           oc = (OsCommPtr) client->osPrivate;
+            struct pollfd       poll_fd;
 
-    notime.tv_sec = 0;
-    notime.tv_usec = 0;
+            poll_fd.fd = oc->fd;
+            poll_fd.events = POLLIN|POLLOUT;
 
-#ifndef WIN32
-    for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
-        mask = AllClients.fds_bits[i];
-        while (mask) {
-            curoff = mffs(mask) - 1;
-            curclient = curoff + (i * (sizeof(fd_mask) * 8));
-            FD_ZERO(&tmask);
-            FD_SET(curclient, &tmask);
             do {
-                r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
+                r = poll(&poll_fd, 1, 0);
             } while (r < 0 && (errno == EINTR || errno == EAGAIN));
             if (r < 0)
-                if (ConnectionTranslation[curclient] > 0)
-                    CloseDownClient(clients[ConnectionTranslation[curclient]]);
-            mask &= ~((fd_mask) 1 << curoff);
+                CloseDownClient(client);
         }
     }
-#else
-    XFD_COPYSET(&AllClients, &savedAllClients);
-    for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) {
-        curclient = XFD_FD(&savedAllClients, i);
-        FD_ZERO(&tmask);
-        FD_SET(curclient, &tmask);
-        do {
-            r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
-        } while (r < 0 && (errno == EINTR || errno == EAGAIN));
-        if (r < 0)
-            if (GetConnectionTranslation(curclient) > 0)
-                CloseDownClient(clients[GetConnectionTranslation(curclient)]);
-    }
-#endif
 }
 
 /*****************
@@ -1045,28 +1007,22 @@ CloseDownConnection(ClientPtr client)
 }
 
 struct notify_fd {
-    struct xorg_list list;
-    int fd;
     int mask;
     NotifyFdProcPtr notify;
     void *data;
 };
 
-static struct xorg_list notify_fds;
+/*****************
+ * HandleNotifyFd
+ *    A poll callback to be called when the registered
+ *    file descriptor is ready.
+ *****************/
 
-void
-InitNotifyFds(void)
+static void
+HandleNotifyFd(int fd, int xevents, void *data)
 {
-    struct notify_fd *s, *next;
-    static int been_here;
-
-    if (been_here)
-        xorg_list_for_each_entry_safe(s, next, &notify_fds, list)
-            RemoveNotifyFd(s->fd);
-
-    xorg_list_init(&notify_fds);
-    NumNotifyWriteFd = 0;
-    been_here = 1;
+    struct notify_fd *n = data;
+    n->notify(fd, xevents, n->data);
 }
 
 /*****************
@@ -1079,56 +1035,32 @@ Bool
 SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
 {
     struct notify_fd *n;
-    int changes;
-
-    xorg_list_for_each_entry(n, &notify_fds, list)
-        if (n->fd == fd)
-            break;
 
-    if (&n->list == &notify_fds) {
+    n = ospoll_data(server_poll, fd);
+    if (!n) {
         if (mask == 0)
             return TRUE;
 
         n = calloc(1, sizeof (struct notify_fd));
         if (!n)
             return FALSE;
-        n->fd = fd;
-        xorg_list_add(&n->list, &notify_fds);
-    }
-
-    changes = n->mask ^ mask;
-
-    if (changes & X_NOTIFY_READ) {
-        if (mask & X_NOTIFY_READ) {
-            FD_SET(fd, &NotifyReadFds);
-            FD_SET(fd, &AllSockets);
-            if (GrabInProgress)
-                FD_SET(fd, &SavedAllSockets);
-        } else {
-            FD_CLR(fd, &AllSockets);
-            if (GrabInProgress)
-                FD_CLR(fd, &SavedAllSockets);
-            FD_CLR(fd, &NotifyReadFds);
-        }
-    }
-
-    if (changes & X_NOTIFY_WRITE) {
-        if (mask & X_NOTIFY_WRITE) {
-            FD_SET(fd, &NotifyWriteFds);
-            if (!NumNotifyWriteFd++)
-                AnyWritesPending = TRUE;
-        } else {
-            FD_CLR(fd, &NotifyWriteFds);
-            if (!--NumNotifyWriteFd)
-                if (!XFD_ANYSET(&ClientsWriteBlocked))
-                    AnyWritesPending = FALSE;
-        }
+        ospoll_add(server_poll, fd,
+                   ospoll_trigger_level,
+                   HandleNotifyFd,
+                   n);
     }
 
     if (mask == 0) {
-        xorg_list_del(&n->list);
+        ospoll_remove(server_poll, fd);
         free(n);
     } else {
+        int listen = mask & ~n->mask;
+        int mute = n->mask & ~mask;
+
+        if (listen)
+            ospoll_listen(server_poll, fd, listen);
+        if (mute)
+            ospoll_mute(server_poll, fd, mute);
         n->mask = mask;
         n->data = data;
         n->notify = notify;
@@ -1138,28 +1070,6 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
 }
 
 /*****************
- * HandlNotifyFds
- *    A WorkProc to be called when any of the registered
- *    file descriptors are readable.
- *****************/
-
-void
-HandleNotifyFds(void)
-{
-    struct notify_fd *n, *next;
-
-    xorg_list_for_each_entry_safe(n, next, &notify_fds, list) {
-        int ready = 0;
-        if ((n->mask & X_NOTIFY_READ) && FD_ISSET(n->fd, &LastSelectMask))
-            ready |= X_NOTIFY_READ;
-        if ((n->mask & X_NOTIFY_WRITE) & FD_ISSET(n->fd, &LastSelectWriteMask))
-            ready |= X_NOTIFY_WRITE;
-        if (ready != 0)
-            n->notify(n->fd, ready, n->data);
-    }
-}
-
-/*****************
  * OnlyListenToOneClient:
  *    Only accept requests from  one client.  Continue to handle new
  *    connections, but don't take any protocol requests from the new
@@ -1172,30 +1082,17 @@ HandleNotifyFds(void)
 int
 OnlyListenToOneClient(ClientPtr client)
 {
-    OsCommPtr oc = (OsCommPtr) client->osPrivate;
-    int rc, connection = oc->fd;
+    int rc;
 
     rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
     if (rc != Success)
         return rc;
 
     if (!GrabInProgress) {
-        XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
-        XFD_ANDSET(&ClientsWithInput,
-                   &ClientsWithInput, &GrabImperviousClients);
-        if (FD_ISSET(connection, &SavedClientsWithInput)) {
-            FD_CLR(connection, &SavedClientsWithInput);
-            FD_SET(connection, &ClientsWithInput);
-        }
-        XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
-        XFD_COPYSET(&AllSockets, &SavedAllSockets);
-        XFD_COPYSET(&AllClients, &SavedAllClients);
-        XFD_UNSET(&AllSockets, &AllClients);
-        XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
-        FD_SET(connection, &AllClients);
-        XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
         GrabInProgress = client->index;
+        set_poll_clients();
     }
+
     return rc;
 }
 
@@ -1208,10 +1105,8 @@ void
 ListenToAllClients(void)
 {
     if (GrabInProgress) {
-        XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
-        XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
-        XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
         GrabInProgress = 0;
+        set_poll_clients();
     }
 }
 
@@ -1225,7 +1120,6 @@ void
 IgnoreClient(ClientPtr client)
 {
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
-    int connection = oc->fd;
 
     client->ignoreCount++;
     if (client->ignoreCount > 1)
@@ -1233,25 +1127,9 @@ IgnoreClient(ClientPtr client)
 
     isItTimeToYield = TRUE;
     mark_client_not_ready(client);
-    if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
-        if (FD_ISSET(connection, &ClientsWithInput))
-            FD_SET(connection, &IgnoredClientsWithInput);
-        else
-            FD_CLR(connection, &IgnoredClientsWithInput);
-        FD_CLR(connection, &ClientsWithInput);
-        FD_CLR(connection, &AllSockets);
-        FD_CLR(connection, &AllClients);
-        FD_CLR(connection, &LastSelectMask);
-    }
-    else {
-        if (FD_ISSET(connection, &SavedClientsWithInput))
-            FD_SET(connection, &IgnoredClientsWithInput);
-        else
-            FD_CLR(connection, &IgnoredClientsWithInput);
-        FD_CLR(connection, &SavedClientsWithInput);
-        FD_CLR(connection, &SavedAllSockets);
-        FD_CLR(connection, &SavedAllClients);
-    }
+
+    oc->flags |= OS_COMM_IGNORED;
+    set_poll_client(client);
 }
 
 /****************
@@ -1263,28 +1141,15 @@ void
 AttendClient(ClientPtr client)
 {
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
-    int connection = oc->fd;
 
     client->ignoreCount--;
     if (client->ignoreCount)
         return;
 
-    if (!GrabInProgress || GrabInProgress == client->index ||
-        FD_ISSET(connection, &GrabImperviousClients)) {
-        FD_SET(connection, &AllClients);
-        FD_SET(connection, &AllSockets);
-        FD_SET(connection, &LastSelectMask);
-        if (FD_ISSET(connection, &IgnoredClientsWithInput)) {
-            FD_SET(connection, &ClientsWithInput);
-            mark_client_ready(client);
-        }
-    }
-    else {
-        FD_SET(connection, &SavedAllClients);
-        FD_SET(connection, &SavedAllSockets);
-        if (FD_ISSET(connection, &IgnoredClientsWithInput))
-            FD_SET(connection, &SavedClientsWithInput);
-    }
+    oc->flags &= ~OS_COMM_IGNORED;
+    set_poll_client(client);
+    if (listen_to_client(client))
+        mark_client_ready(client);
 }
 
 /* make client impervious to grabs; assume only executing client calls this */
@@ -1293,9 +1158,9 @@ void
 MakeClientGrabImpervious(ClientPtr client)
 {
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
-    int connection = oc->fd;
 
-    FD_SET(connection, &GrabImperviousClients);
+    oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
+    set_poll_client(client);
 
     if (ServerGrabCallback) {
         ServerGrabInfoRec grabinfo;
@@ -1312,18 +1177,10 @@ void
 MakeClientGrabPervious(ClientPtr client)
 {
     OsCommPtr oc = (OsCommPtr) client->osPrivate;
-    int connection = oc->fd;
 
-    FD_CLR(connection, &GrabImperviousClients);
-    if (GrabInProgress && (GrabInProgress != client->index)) {
-        if (FD_ISSET(connection, &ClientsWithInput)) {
-            FD_SET(connection, &SavedClientsWithInput);
-            FD_CLR(connection, &ClientsWithInput);
-        }
-        FD_CLR(connection, &AllSockets);
-        FD_CLR(connection, &AllClients);
-        isItTimeToYield = TRUE;
-    }
+    oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
+    set_poll_client(client);
+    isItTimeToYield = TRUE;
 
     if (ServerGrabCallback) {
         ServerGrabInfoRec grabinfo;
@@ -1405,3 +1262,46 @@ AddClientOnOpenFD(int fd)
 
     return TRUE;
 }
+
+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))
+        ospoll_listen(server_poll, oc->fd, X_NOTIFY_READ);
+    else
+        ospoll_mute(server_poll, oc->fd, X_NOTIFY_READ);
+}
+
+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);
+    }
+}
diff --git a/os/io.c b/os/io.c
index 36527dc..88edf12 100644
--- a/os/io.c
+++ b/os/io.c
@@ -74,7 +74,6 @@ SOFTWARE.
 #include <X11/Xproto.h>
 #include "os.h"
 #include "osdep.h"
-#include <X11/Xpoll.h>
 #include "opaque.h"
 #include "dixstruct.h"
 #include "misc.h"
@@ -188,7 +187,7 @@ static void
 YieldControlNoInput(int fd)
 {
     YieldControl();
-    FD_CLR(fd, &ClientsWithInput);
+    ospoll_reset_events(server_poll, fd);
 }
 
 static void
@@ -439,24 +438,8 @@ ReadRequestFromClient(ClientPtr client)
      */
 
     gotnow -= needed;
-    if (gotnow >= sizeof(xReq)) {
-        request = (xReq *) (oci->bufptr + needed);
-        if (gotnow >= (result = (get_req_len(request, client) << 2))
-            && (result ||
-                (client->big_requests &&
-                 (gotnow >= sizeof(xBigReq) &&
-                  gotnow >= (get_big_req_len(request, client) << 2))))
-            )
-            FD_SET(fd, &ClientsWithInput);
-        else {
-            FD_CLR(fd, &ClientsWithInput);
-        }
-    }
-    else {
-        if (!gotnow)
-            AvailableInput = oc;
-        FD_CLR(fd, &ClientsWithInput);
-    }
+    if (!gotnow)
+        AvailableInput = oc;
     if (move_header) {
         request = (xReq *) oci->bufptr;
         oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
@@ -549,7 +532,7 @@ InsertFakeRequest(ClientPtr client, char *data, int count)
     gotnow += count;
     if ((gotnow >= sizeof(xReq)) &&
         (gotnow >= (int) (get_req_len((xReq *) oci->bufptr, client) << 2)))
-        FD_SET(fd, &ClientsWithInput);
+        mark_client_ready(client);
     else
         YieldControlNoInput(fd);
     return TRUE;
@@ -589,12 +572,8 @@ ResetCurrentRequest(ClientPtr client)
             }
         }
         if (gotnow >= (needed << 2)) {
-            if (FD_ISSET(fd, &AllClients)) {
-                FD_SET(fd, &ClientsWithInput);
-            }
-            else {
-                FD_SET(fd, &IgnoredClientsWithInput);
-            }
+            if (listen_to_client(client))
+                mark_client_ready(client);
             YieldControl();
         }
         else
@@ -615,16 +594,10 @@ ResetCurrentRequest(ClientPtr client)
 void
 FlushAllOutput(void)
 {
-    register int index, base;
-    register fd_mask mask;      /* raphael */
     OsCommPtr oc;
-    register ClientPtr client;
+    register ClientPtr client, tmp;
     Bool newoutput = NewOutputPending;
 
-#if defined(WIN32)
-    fd_set newOutputPending;
-#endif
-
     if (FlushCallback)
         CallCallbacks(&FlushCallback, NULL);
 
@@ -639,48 +612,14 @@ FlushAllOutput(void)
     CriticalOutputPending = FALSE;
     NewOutputPending = FALSE;
 
-#ifndef WIN32
-    for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) {
-        mask = OutputPending.fds_bits[base];
-        OutputPending.fds_bits[base] = 0;
-        while (mask) {
-            index = ffs(mask) - 1;
-            mask &= ~lowbit(mask);
-            if ((index =
-                 ConnectionTranslation[(base * (sizeof(fd_mask) * 8)) +
-                                       index]) == 0)
-                continue;
-            client = clients[index];
-            if (client->clientGone)
-                continue;
-            oc = (OsCommPtr) client->osPrivate;
-            if (FD_ISSET(oc->fd, &ClientsWithInput)) {
-                FD_SET(oc->fd, &OutputPending); /* set the bit again */
-                NewOutputPending = TRUE;
-            }
-            else
-                (void) FlushClient(client, oc, (char *) NULL, 0);
-        }
-    }
-#else                           /* WIN32 */
-    FD_ZERO(&newOutputPending);
-    for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) {
-        index = XFD_FD(&OutputPending, base);
-        if ((index = GetConnectionTranslation(index)) == 0)
-            continue;
-        client = clients[index];
+    xorg_list_for_each_entry_safe(client, tmp, &output_pending_clients, output_pending) {
         if (client->clientGone)
             continue;
-        oc = (OsCommPtr) client->osPrivate;
-        if (FD_ISSET(oc->fd, &ClientsWithInput)) {
-            FD_SET(oc->fd, &newOutputPending);  /* set the bit again */
-            NewOutputPending = TRUE;
-        }
-        else
+        if (!client_is_ready(client)) {
+            oc = (OsCommPtr) client->osPrivate;
             (void) FlushClient(client, oc, (char *) NULL, 0);
+        }
     }
-    XFD_COPYSET(&newOutputPending, &OutputPending);
-#endif                          /* WIN32 */
 }
 
 void
@@ -822,8 +761,8 @@ WriteToClient(ClientPtr who, int count, const void *__buf)
     }
 #endif
     if (oco->count == 0 || oco->count + count + padBytes > oco->size) {
-        FD_CLR(oc->fd, &OutputPending);
-        if (!XFD_ANYSET(&OutputPending)) {
+        output_pending_clear(who);
+        if (!any_output_pending()) {
             CriticalOutputPending = FALSE;
             NewOutputPending = FALSE;
         }
@@ -835,7 +774,7 @@ WriteToClient(ClientPtr who, int count, const void *__buf)
     }
 
     NewOutputPending = TRUE;
-    FD_SET(oc->fd, &OutputPending);
+    output_pending_mark(who);
     memmove((char *) oco->buf + oco->count, buf, count);
     oco->count += count;
     if (padBytes) {
@@ -859,7 +798,6 @@ int
 FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
 {
     ConnectionOutputPtr oco = oc->output;
-    int connection = oc->fd;
     XtransConnInfo trans_conn = oc->trans_conn;
     struct iovec iov[3];
     static char padBuffer[3];
@@ -932,8 +870,7 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
             /* If we've arrived here, then the client is stuffed to the gills
                and not ready to accept more.  Make a note of it and buffer
                the rest. */
-            FD_SET(connection, &ClientsWriteBlocked);
-            AnyWritesPending = TRUE;
+            output_pending_mark(who);
 
             if (written < oco->count) {
                 if (written > 0) {
@@ -973,6 +910,8 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
                         extraBuf + written, len);
 
             oco->count = notWritten;    /* this will include the pad */
+            ospoll_listen(server_poll, oc->fd, X_NOTIFY_WRITE);
+
             /* return only the amount explicitly requested */
             return extraCount;
         }
@@ -995,12 +934,8 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
 
     /* everything was flushed out */
     oco->count = 0;
-    /* check to see if this client was write blocked */
-    if (AnyWritesPending) {
-        FD_CLR(oc->fd, &ClientsWriteBlocked);
-        if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
-            AnyWritesPending = FALSE;
-    }
+    output_pending_clear(who);
+
     if (oco->size > BUFWATERMARK) {
         free(oco->buf);
         free(oco);
diff --git a/os/osdep.h b/os/osdep.h
index 9dbf0fb..df0abeb 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -162,8 +162,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 */ ,
@@ -173,24 +177,13 @@ extern int FlushClient(ClientPtr /*who */ ,
 extern void FreeOsBuffers(OsCommPtr     /*oc */
     );
 
-extern void InitNotifyFds(void);
-
-extern void HandleNotifyFds(void);
-
 #include "dix.h"
+#include "ospoll.h"
+
+extern struct ospoll    *server_poll;
 
-extern fd_set AllSockets;
-extern fd_set AllClients;
-extern fd_set LastSelectMask;
-extern fd_set LastSelectWriteMask;
-extern fd_set WellKnownConnections;
-extern fd_set EnabledDevices;
-extern fd_set NotifyReadFds;
-extern fd_set NotifyWriteFds;
-extern fd_set ClientsWithInput;
-extern fd_set ClientsWriteBlocked;
-extern fd_set OutputPending;
-extern fd_set IgnoredClientsWithInput;
+Bool
+listen_to_client(ClientPtr client);
 
 #if !defined(WIN32) || defined(__CYGWIN__)
 extern int *ConnectionTranslation;
@@ -201,8 +194,6 @@ extern void ClearConnectionTranslation(void);
 #endif
 
 extern Bool NewOutputPending;
-extern Bool AnyWritesPending;
-extern Bool NumNotifyWriteFd;
 
 extern WorkQueuePtr workQueue;
 
diff --git a/os/osinit.c b/os/osinit.c
index 629fef5..ab9c1d6 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -195,7 +195,9 @@ OsInit(void)
 #ifdef BUSFAULT
         busfault_init();
 #endif
-        InitNotifyFds();
+        server_poll = ospoll_create();
+        if (!server_poll)
+            FatalError("failed to allocate poll structure");
 
 #ifdef HAVE_BACKTRACE
         /*
diff --git a/os/xdmcp.c b/os/xdmcp.c
index 2cb8d76..906c959 100644
--- a/os/xdmcp.c
+++ b/os/xdmcp.c
@@ -39,7 +39,6 @@
 #include <X11/X.h>
 #include <X11/Xmd.h>
 #include "misc.h"
-#include <X11/Xpoll.h>
 #include "osdep.h"
 #include "input.h"
 #include "dixstruct.h"
commit 8f1edf4bd3a1f050ce9eeb5eac45dd1a8f7a6d5e
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 19 13:59:54 2016 -0700

    dix: Use list for ready clients
    
    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>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 7eb200d..3b9600e 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;
@@ -445,8 +490,7 @@ Dispatch(void)
                 }
             }
             FlushAllOutput();
-            client = clients[clientReady[nready]];
-            if (client)
+            if (client == SmartLastClient)
                 client->smart_stop_tick = SmartScheduleTime;
         }
         dispatchException &= ~DE_PRIORITYCHANGE;
@@ -455,7 +499,6 @@ Dispatch(void)
     ddxBeforeReset();
 #endif
     KillAllClients();
-    free(clientReady);
     dispatchException &= ~DE_RESET;
     SmartScheduleLatencyLimited = 0;
     ResetOsBuffers();
@@ -1055,6 +1098,7 @@ ProcGrabServer(ClientPtr client)
         return rc;
     grabState = GrabActive;
     grabClient = client;
+    mark_client_grab(client);
 
     if (ServerGrabCallback) {
         ServerGrabInfoRec grabinfo;
@@ -1074,6 +1118,7 @@ UngrabServer(ClientPtr client)
 
     grabState = GrabNone;
     ListenToAllClients();
+    mark_client_ungrab();
     for (i = mskcnt; --i >= 0 && !grabWaiters[i];);
     if (i >= 0) {
         i <<= 5;
@@ -3365,6 +3410,7 @@ CloseDownClient(ClientPtr client)
         if (grabState != GrabNone && grabClient == client) {
             UngrabServer(client);
         }
+        mark_client_not_ready(client);
         BITCLEAR(grabWaiters, client->index);
         DeleteClientFromAnySelections(client);
         ReleaseActiveGrabs(client);
@@ -3454,6 +3500,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 b0a068e..765562c 100644
--- a/include/os.h
+++ b/include/os.h
@@ -96,8 +96,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 7bdd399..8164c30 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 ad949c9..9e0c976 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -1232,6 +1232,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);
@@ -1273,8 +1274,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);
diff --git a/os/io.c b/os/io.c
index 596deff..36527dc 100644
--- a/os/io.c
+++ b/os/io.c
@@ -354,6 +354,7 @@ ReadRequestFromClient(ClientPtr client)
                                  oci->size - oci->bufcnt);
         if (result <= 0) {
             if ((result < 0) && ETEST(errno)) {
+                mark_client_not_ready(client);
 #if defined(SVR4) && defined(__i386__) && !defined(__sun)
                 if (0)
 #endif
commit d6eff3c31e8289881a3aa9b858e5710d0f741db0
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 26 10:20:45 2016 -0700

    os: Add ospoll interface [v2]
    
    This provides a wrapper around poll or epoll providing a
    callback-based interface for monitoring activity on a large set of
    file descriptors.
    
    v2: use xserver_poll API instead of poll. Don't use WSAPoll as
        that is broken.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 58fcf79..2b93a4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -219,7 +219,7 @@ dnl Checks for library functions.
 AC_CHECK_FUNCS([backtrace ffs geteuid getuid issetugid getresuid \
 	getdtablesize getifaddrs getpeereid getpeerucred getprogname getzoneid \
 	mmap posix_fallocate seteuid shmctl64 strncasecmp vasprintf vsnprintf \
-	walkcontext setitimer poll])
+	walkcontext setitimer poll epoll_create1])
 AC_CONFIG_LIBOBJ_DIR([os])
 AC_REPLACE_FUNCS([reallocarray strcasecmp strcasestr strlcat strlcpy strndup])
 AM_CONDITIONAL(POLL, [test "x$ac_cv_func_poll" = "xyes"])
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index bf2a9ed..d49af92 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -530,4 +530,7 @@
 /* Have poll() */
 #undef HAVE_POLL
 
+/* Have epoll_create1() */
+#undef HAVE_EPOLL_CREATE1
+
 #endif /* _DIX_CONFIG_H_ */
diff --git a/os/Makefile.am b/os/Makefile.am
index c449076..d97ba30 100644
--- a/os/Makefile.am
+++ b/os/Makefile.am
@@ -22,6 +22,7 @@ libos_la_SOURCES = 	\
 	oscolor.c	\
 	osdep.h		\
 	osinit.c	\
+	ospoll.c	\
 	utils.c		\
 	xdmauth.c	\
 	xsha1.c		\
diff --git a/os/ospoll.c b/os/ospoll.c
new file mode 100644
index 0000000..3c2b80b
--- /dev/null
+++ b/os/ospoll.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright © 2016 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "misc.h"               /* for typedef of pointer */
+#include "ospoll.h"
+#include "list.h"
+
+#if !HAVE_OSPOLL && HAVE_EPOLL_CREATE1
+#include <sys/epoll.h>
+#define EPOLL           1
+#define HAVE_OSPOLL     1
+#endif
+
+#if !HAVE_OSPOLL
+#include "xserver_poll.h"
+#define POLL            1
+#define HAVE_OSPOLL     1
+#endif
+
+#if EPOLL
+#include <sys/epoll.h>
+
+/* epoll-based implementation */
+struct ospollfd {
+    int                 fd;
+    int                 xevents;
+    enum ospoll_trigger trigger;
+    void                (*callback)(int fd, int xevents, void *data);
+    void                *data;
+};
+
+struct ospoll {
+    int                 epoll_fd;
+    struct ospollfd     **fds;
+    int                 num;
+    int                 size;
+};
+
+#endif
+
+#if POLL
+
+/* poll-based implementation */
+struct ospollfd {
+    short               revents;
+    enum ospoll_trigger trigger;
+    void                (*callback)(int fd, int revents, void *data);
+    void                *data;
+};
+
+struct ospoll {
+    struct pollfd       *fds;
+    struct ospollfd     *osfds;
+    int                 num;
+    int                 size;
+};
+
+#endif
+
+/* Binary search for the specified file descriptor
+ *
+ * Returns position if found
+ * Returns -position - 1 if not found
+ */
+
+static int
+ospoll_find(struct ospoll *ospoll, int fd)
+{
+    int lo = 0;
+    int hi = ospoll->num - 1;
+
+    while (lo <= hi) {
+        int m = (lo + hi) >> 1;
+#if EPOLL
+        int t = ospoll->fds[m]->fd;
+#endif
+#if POLL
+        int t = ospoll->fds[m].fd;
+#endif
+
+        if (t < fd)
+            lo = m + 1;
+        else if (t > fd)
+            hi = m - 1;
+        else
+            return m;
+    }
+    return -(lo + 1);
+}
+
+/* Insert an element into an array
+ *
+ * base: base address of array
+ * num:  number of elements in the array before the insert
+ * size: size of each element
+ * pos:  position to insert at
+ */
+static inline void
+array_insert(void *base, size_t num, size_t size, size_t pos)
+{
+    char *b = base;
+
+    memmove(b + (pos+1) * size,
+            b + pos * size,
+            (num - pos) * size);
+}
+
+/* Delete an element from an array
+ *
+ * base: base address of array
+ * num:  number of elements in the array before the delete
+ * size: size of each element
+ * pos:  position to delete from
+ */
+static inline void
+array_delete(void *base, size_t num, size_t size, size_t pos)
+{
+    char *b = base;
+
+    memmove(b + pos * size, b + (pos + 1) * size,
+            (num - pos - 1) * size);
+}
+
+
+struct ospoll *
+ospoll_create(void)
+{
+#if EPOLL
+    struct ospoll       *ospoll = calloc(1, sizeof (struct ospoll));
+
+    ospoll->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+    if (ospoll->epoll_fd < 0) {
+        free (ospoll);
+        return NULL;
+    }
+    return ospoll;
+#endif
+#if POLL
+    return calloc(1, sizeof (struct ospoll));
+#endif
+}
+
+void
+ospoll_destroy(struct ospoll *ospoll)
+{
+#if EPOLL
+    if (ospoll) {
+        assert (ospoll->num == 0);
+        close(ospoll->epoll_fd);
+        free(ospoll->fds);
+        free(ospoll);
+    }
+#endif
+#if POLL
+    if (ospoll) {
+        assert (ospoll->num == 0);
+        free (ospoll->fds);
+        free (ospoll->osfds);
+        free (ospoll);
+    }
+#endif
+}
+
+Bool
+ospoll_add(struct ospoll *ospoll, int fd,
+           enum ospoll_trigger trigger,
+           void (*callback)(int fd, int xevents, void *data),
+           void *data)
+{
+    int pos = ospoll_find(ospoll, fd);
+#if EPOLL
+    struct ospollfd *osfd;
+
+    if (pos < 0) {
+
+        struct epoll_event ev;
+
+        osfd = calloc(1, sizeof (struct ospollfd));
+        if (!osfd)
+            return FALSE;
+
+        if (ospoll->num >= ospoll->size) {
+            struct ospollfd **new_fds;
+            int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
+
+            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
+            if (!new_fds) {
+                free (osfd);
+                return FALSE;
+            }
+            ospoll->fds = new_fds;
+            ospoll->size = new_size;
+        }
+
+        ev.events = 0;
+        ev.data.ptr = osfd;
+        if (trigger == ospoll_trigger_edge)
+            ev.events |= EPOLLET;
+        if (epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+            free(osfd);
+            return FALSE;
+        }
+        osfd->fd = fd;
+        osfd->xevents = 0;
+
+        pos = -pos - 1;
+        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
+        ospoll->fds[pos] = osfd;
+        ospoll->num++;
+    } else {
+        osfd = ospoll->fds[pos];
+    }
+    osfd->data = data;
+    osfd->callback = callback;
+    osfd->trigger = trigger;
+#endif
+#if POLL
+    if (pos < 0) {
+        if (ospoll->num == ospoll->size) {
+            struct pollfd   *new_fds;
+            struct ospollfd *new_osfds;
+            int             new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
+
+            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
+            if (!new_fds)
+                return FALSE;
+            ospoll->fds = new_fds;
+            new_osfds = reallocarray(ospoll->osfds, new_size, sizeof (ospoll->osfds[0]));
+            if (!new_osfds)
+                return FALSE;
+            ospoll->osfds = new_osfds;
+            ospoll->size = new_size;
+        }
+        pos = -pos - 1;
+        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
+        array_insert(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
+        ospoll->num++;
+
+        ospoll->fds[pos].fd = fd;
+        ospoll->fds[pos].events = 0;
+        ospoll->fds[pos].revents = 0;
+        ospoll->osfds[pos].revents = 0;
+    }
+    ospoll->osfds[pos].trigger = trigger;
+    ospoll->osfds[pos].callback = callback;
+    ospoll->osfds[pos].data = data;
+#endif
+    return TRUE;
+}
+
+void
+ospoll_remove(struct ospoll *ospoll, int fd)
+{
+    int pos = ospoll_find(ospoll, fd);
+
+    pos = ospoll_find(ospoll, fd);
+    if (pos >= 0) {
+#if EPOLL
+        struct ospollfd *osfd = ospoll->fds[pos];
+        struct epoll_event ev;
+        ev.events = 0;
+        ev.data.ptr = osfd;
+        (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_DEL, fd, &ev);
+
+        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
+        ospoll->num--;
+        free (osfd);
+#endif
+#if POLL
+        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
+        array_delete(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
+        ospoll->num--;
+#endif
+    }
+}
+
+#if EPOLL
+static void
+epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
+{
+    struct epoll_event ev;
+    ev.events = 0;
+    if (osfd->xevents & X_NOTIFY_READ)
+        ev.events |= EPOLLIN;
+    if (osfd->xevents & X_NOTIFY_WRITE)
+        ev.events |= EPOLLOUT;
+    if (osfd->trigger == ospoll_trigger_edge)
+        ev.events |= EPOLLET;
+    ev.data.ptr = osfd;
+    (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_MOD, osfd->fd, &ev);
+}
+#endif
+
+void
+ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
+{
+    int pos = ospoll_find(ospoll, fd);
+
+    if (pos >= 0) {
+#if EPOLL
+        struct ospollfd *osfd = ospoll->fds[pos];
+        osfd->xevents |= xevents;
+        epoll_mod(ospoll, osfd);
+#endif
+#if POLL
+        if (xevents & X_NOTIFY_READ)
+            ospoll->fds[pos].events |= POLLIN;
+        if (xevents & X_NOTIFY_WRITE)
+            ospoll->fds[pos].events |= POLLOUT;
+#endif
+    }
+}
+
+void
+ospoll_mute(struct ospoll *ospoll, int fd, int xevents)
+{
+    int pos = ospoll_find(ospoll, fd);
+
+    if (pos >= 0) {
+#if EPOLL
+        struct ospollfd *osfd = ospoll->fds[pos];
+        osfd->xevents &= ~xevents;
+        epoll_mod(ospoll, osfd);
+#endif
+#if POLL
+        if (xevents & X_NOTIFY_READ)
+            ospoll->fds[pos].events &= ~POLLIN;
+        if (xevents & X_NOTIFY_WRITE)
+            ospoll->fds[pos].events &= ~POLLOUT;
+#endif
+    }
+}
+
+
+int
+ospoll_wait(struct ospoll *ospoll, int timeout)
+{
+    int nready;
+#if EPOLL
+#define MAX_EVENTS      256
+    struct epoll_event events[MAX_EVENTS];
+    int i;
+
+    nready = epoll_wait(ospoll->epoll_fd, events, MAX_EVENTS, timeout);
+    for (i = 0; i < nready; i++) {
+        struct epoll_event *ev = &events[i];
+        struct ospollfd *osfd = ev->data.ptr;
+        uint32_t revents = ev->events;
+        int xevents = 0;
+
+        if (revents & EPOLLIN)
+            xevents |= X_NOTIFY_READ;
+        if (revents & EPOLLOUT)
+            xevents |= X_NOTIFY_WRITE;
+        if (revents & (~(EPOLLIN|EPOLLOUT)))
+            xevents |= X_NOTIFY_ERROR;
+
+        osfd->callback(osfd->fd, xevents, osfd->data);
+    }
+#endif
+#if POLL
+    nready = xserver_poll(ospoll->fds, ospoll->num, timeout);
+    if (nready > 0) {
+        int f;
+        for (f = 0; f < ospoll->num; f++) {
+            short revents = ospoll->fds[f].revents;
+            short oldevents = ospoll->osfds[f].revents;
+
+            ospoll->osfds[f].revents = (revents & (POLLIN|POLLOUT));
+            if (ospoll->osfds[f].trigger == ospoll_trigger_edge)
+                revents &= ~oldevents;
+            if (revents) {
+                int    xevents = 0;
+                if (revents & POLLIN)
+                    xevents |= X_NOTIFY_READ;
+                if (revents & POLLOUT)
+                    xevents |= X_NOTIFY_WRITE;
+                if (revents & (~(POLLIN|POLLOUT)))
+                    xevents |= X_NOTIFY_ERROR;
+                ospoll->osfds[f].callback(ospoll->fds[f].fd, xevents,
+                                          ospoll->osfds[f].data);
+            }
+        }
+    }
+#endif
+    return nready;
+}
+
+void
+ospoll_reset_events(struct ospoll *ospoll, int fd)
+{
+#if POLL
+    int pos = ospoll_find(ospoll, fd);
+
+    if (pos < 0)
+        return;
+
+    ospoll->osfds[pos].revents = 0;
+#endif
+}
+
+void *
+ospoll_data(struct ospoll *ospoll, int fd)
+{
+    int pos = ospoll_find(ospoll, fd);
+
+    if (pos < 0)
+        return NULL;
+#if EPOLL
+    return ospoll->fds[pos]->data;
+#endif
+#if POLL
+    return ospoll->osfds[pos].data;
+#endif
+}
diff --git a/os/ospoll.h b/os/ospoll.h
new file mode 100644
index 0000000..cdc45f4
--- /dev/null
+++ b/os/ospoll.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2016 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _OSPOLL_H_
+#define _OSPOLL_H_
+
+/* Forward declaration */
+struct ospoll;
+
+/**
+ * ospoll_wait trigger mode
+ *
+ * @ospoll_trigger_edge
+ *      Trigger only when going from no data available
+ *      to data available.
+ *
+ * @ospoll_trigger_level
+ *      Trigger whenever there is data available
+ */
+enum ospoll_trigger {
+    ospoll_trigger_edge,
+    ospoll_trigger_level
+};
+
+/**
+ * Create a new ospoll structure
+ */
+struct ospoll *
+ospoll_create(void);
+
+/**
+ * Destroy an ospoll structure
+ *
+ * @param       ospoll          ospoll to destroy
+ */
+void
+ospoll_destroy(struct ospoll *ospoll);
+
+/**
+ * Add a file descriptor to monitor
+ *
+ * @param       ospoll          ospoll to add to
+ * @param       fd              File descriptor to monitor
+ * @param       trigger         Trigger mode for ospoll_wait
+ * @param       callback        Function to call when triggered
+ * @param       data            Extra data to pass callback
+ */
+Bool
+ospoll_add(struct ospoll *ospoll, int fd,
+           enum ospoll_trigger trigger,
+           void (*callback)(int fd, int xevents, void *data),
+           void *data);
+
+/**
+ * Remove a monitored file descriptor
+ *
+ * @param       ospoll          ospoll to remove from
+ * @param       fd              File descriptor to stop monitoring
+ */
+void
+ospoll_remove(struct ospoll *ospoll, int fd);
+
+/**
+ * Listen on additional events
+ *
+ * @param       ospoll          ospoll monitoring fd
+ * @param       fd              File descriptor to change
+ * @param       events          Additional events to trigger on
+ */
+void
+ospoll_listen(struct ospoll *ospoll, int fd, int xevents);
+
+/**
+ * Stop listening on events
+ *
+ * @param       ospoll          ospoll monitoring fd
+ * @param       fd              File descriptor to change
+ * @param       events          events to stop triggering on
+ */
+void
+ospoll_mute(struct ospoll *ospoll, int fd, int xevents);
+
+/**
+ * Wait for events
+ *
+ * @param       ospoll          ospoll to wait on
+ * @param       timeout         < 0 wait forever
+ *                              = 0 check and return
+ *                              > 0 timeout in milliseconds
+ * @return      < 0 error
+ *              = 0 timeout
+ *              > 0 number of events delivered
+ */
+int
+ospoll_wait(struct ospoll *ospoll, int timeout);
+
+/**
+ * Reset edge trigger status
+ *
+ * @param       ospoll          ospoll monitoring fd
+ * @param       fd              file descriptor
+ *
+ * ospoll_reset_events resets the state of an edge-triggered
+ * fd so that ospoll_wait calls will report events again.
+ *
+ * Call this after a read/recv operation reports no more data available.
+ */
+void
+ospoll_reset_events(struct ospoll *ospoll, int fd);
+
+/**
+ * Fetch the data associated with an fd
+ *
+ * @param       ospoll          ospoll monitoring fd
+ * @param       fd              file descriptor
+ *
+ * @return      data parameter passed to ospoll_add call on
+ *              this file descriptor
+ */
+void *
+ospoll_data(struct ospoll *ospoll, int fd);
+
+#endif /* _OSPOLL_H_ */
commit d403aca70a07e1401cb93738f1af5961582a2e47
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Jul 18 15:58:42 2016 -0700

    Switch poll() users to xserver_poll()
    
    This uses the wrapper in case we need to emulate poll with select
    as we do on Windows.
    
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/hw/dmx/input/lnx-ms.c b/hw/dmx/input/lnx-ms.c
index c7a09ca..1a5786c 100644
--- a/hw/dmx/input/lnx-ms.c
+++ b/hw/dmx/input/lnx-ms.c
@@ -76,7 +76,7 @@
 #include <X11/Xos.h>
 #include <errno.h>
 #include <termios.h>
-#include <poll.h>
+#include <xserver_poll.h>
 
 /*****************************************************************************/
 /* Define some macros to make it easier to move this file to another
@@ -135,7 +135,7 @@ msLinuxReadBytes(int fd, unsigned char *buf, int len, int min)
         }
         if (tot % min == 0)
             break;
-        n = poll(&poll_fd, 1, 100);
+        n = xserver_poll(&poll_fd, 1, 100);
         if (n <= 0)
             break;
     }
diff --git a/hw/dmx/input/lnx-ps2.c b/hw/dmx/input/lnx-ps2.c
index 00ccc01..2b6e8d6 100644
--- a/hw/dmx/input/lnx-ps2.c
+++ b/hw/dmx/input/lnx-ps2.c
@@ -73,7 +73,7 @@
 #include <X11/Xos.h>
 #include <errno.h>
 #include <termios.h>
-#include <poll.h>
+#include <xserver_poll.h>
 
 /*****************************************************************************/
 /* Define some macros to make it easier to move this file to another
@@ -131,7 +131,7 @@ ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min)
         }
         if (tot % min == 0)
             break;
-        n = poll(&poll_fd, 1, 100);
+        n = xserver_poll(&poll_fd, 1, 100);
         if (n <= 0)
             break;
     }
diff --git a/hw/kdrive/linux/mouse.c b/hw/kdrive/linux/mouse.c
index 3508b17..6bdd286 100644
--- a/hw/kdrive/linux/mouse.c
+++ b/hw/kdrive/linux/mouse.c
@@ -27,7 +27,7 @@
 #include <termios.h>
 #include <X11/X.h>
 #include <X11/Xproto.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include "inputstr.h"
 #include "scrnintstr.h"
 #include "kdrive.h"
@@ -55,7 +55,7 @@ MouseWaitForReadable(int fd, int timeout)
     poll_fd.fd = fd;
     poll_fd.events = POLLIN;
     for (;;) {
-        n = poll(&poll_fd, 1, timeout);
+        n = xserver_poll(&poll_fd, 1, timeout);
         if (n > 0)
             return TRUE;
         if (n < 0 && (errno == EAGAIN || errno == EINTR)) {
@@ -136,7 +136,7 @@ MouseWaitForWritable(int fd, int timeout)
 
     poll_fd.fd = fd;
     poll_fd.events = POLLOUT;
-    n = poll(&poll_fd, 1, timeout);
+    n = xserver_poll(&poll_fd, 1, timeout);
     if (n > 0)
         return TRUE;
     return FALSE;
diff --git a/hw/kdrive/linux/ms.c b/hw/kdrive/linux/ms.c
index 79e6373..3934682 100644
--- a/hw/kdrive/linux/ms.c
+++ b/hw/kdrive/linux/ms.c
@@ -26,7 +26,7 @@ THE SOFTWARE.
 #endif
 #include <errno.h>
 #include <termios.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include <X11/X.h>
 #include <X11/Xproto.h>
 #include "inputstr.h"
@@ -51,7 +51,7 @@ MsReadBytes(int fd, char *buf, int len, int min)
         }
         if (tot % min == 0)
             break;
-        n = poll(&poll_fd, 1, 100);
+        n = xserver_poll(&poll_fd, 1, 100);
         if (n <= 0)
             break;
     }
diff --git a/hw/kdrive/linux/ps2.c b/hw/kdrive/linux/ps2.c
index 5d4a8eb..4fec024 100644
--- a/hw/kdrive/linux/ps2.c
+++ b/hw/kdrive/linux/ps2.c
@@ -25,7 +25,7 @@
 #endif
 #include <X11/X.h>
 #include <X11/Xproto.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include "inputstr.h"
 #include "scrnintstr.h"
 #include "kdrive.h"
@@ -48,7 +48,7 @@ Ps2ReadBytes(int fd, char *buf, int len, int min)
         }
         if (tot % min == 0)
             break;
-        n = poll(&poll_fd, 1, 100);
+        n = xserver_poll(&poll_fd, 1, 100);
         if (n <= 0)
             break;
     }
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index 9a596de..0093fb5 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -27,7 +27,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -87,7 +87,7 @@ ms_flush_drm_events(ScreenPtr screen)
     int r;
 
     do {
-            r = poll(&p, 1, 0);
+            r = xserver_poll(&p, 1, 0);
     } while (r == -1 && (errno == EINTR || errno == EAGAIN));
 
     /* If there was an error, r will be < 0.  Return that.  If there was
diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c
index 0727887..d5a9ded 100644
--- a/hw/xfree86/drivers/modesetting/vblank.c
+++ b/hw/xfree86/drivers/modesetting/vblank.c
@@ -32,7 +32,6 @@
 #include <unistd.h>
 #include <xf86.h>
 #include <xf86Crtc.h>
-#include <poll.h>
 #include "driver.h"
 #include "drmmode_display.h"
 
diff --git a/hw/xfree86/os-support/shared/posix_tty.c b/hw/xfree86/os-support/shared/posix_tty.c
index d5a70ba..6249a62 100644
--- a/hw/xfree86/os-support/shared/posix_tty.c
+++ b/hw/xfree86/os-support/shared/posix_tty.c
@@ -57,7 +57,7 @@
 #endif
 
 #include <X11/X.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include "xf86.h"
 #include "xf86Priv.h"
 #include "xf86_OSlib.h"
@@ -395,10 +395,10 @@ xf86WaitForInput(int fd, int timeout)
     poll_fd.events = POLLIN;
 
     if (fd >= 0) {
-        SYSCALL(r = poll(&poll_fd, 1, timeout));
+        SYSCALL(r = xserver_poll(&poll_fd, 1, timeout));
     }
     else {
-        SYSCALL(r = poll(&poll_fd, 0, timeout));
+        SYSCALL(r = xserver_poll(&poll_fd, 0, timeout));
     }
     xf86ErrorFVerb(9, "poll returned %d\n", r);
     return r;
@@ -427,7 +427,7 @@ xf86FlushInput(int fd)
 
     poll_fd.fd = fd;
     poll_fd.events = POLLIN;
-    while (poll(&poll_fd, 1, 0) > 0) {
+    while (xserver_poll(&poll_fd, 1, 0) > 0) {
         if (read(fd, &c, sizeof(c)) < 1)
             return 0;
     }
diff --git a/hw/xfree86/os-support/shared/sigio.c b/hw/xfree86/os-support/shared/sigio.c
index 949d1b4..884a71c 100644
--- a/hw/xfree86/os-support/shared/sigio.c
+++ b/hw/xfree86/os-support/shared/sigio.c
@@ -57,7 +57,7 @@
 #endif
 
 #include <X11/X.h>
-#include <poll.h>
+#include <xserver_poll.h>
 #include "xf86.h"
 #include "xf86Priv.h"
 #include "xf86_OSlib.h"
@@ -128,7 +128,7 @@ xf86SIGIO(int sig)
 
     inSignalContext = TRUE;
 
-    SYSCALL(r = poll(xf86SigIOFds, xf86SigIONum, 0));
+    SYSCALL(r = xserver_poll(xf86SigIOFds, xf86SigIONum, 0));
     for (f = 0; r > 0 && f < xf86SigIONum; f++) {
         if (xf86SigIOFds[f].revents & POLLIN) {
             for (i = 0; i < xf86SigIOMax; i++)
diff --git a/hw/xfree86/os-support/solaris/sun_bell.c b/hw/xfree86/os-support/solaris/sun_bell.c
index beb13d2..883728e 100644
--- a/hw/xfree86/os-support/solaris/sun_bell.c
+++ b/hw/xfree86/os-support/solaris/sun_bell.c
@@ -28,7 +28,7 @@
 #include <sys/uio.h>
 #include <limits.h>
 #include <math.h>
-#include <poll.h>
+#include <xserver_poll.h>
 
 #include "xf86.h"
 #include "xf86Priv.h"
@@ -163,7 +163,7 @@ xf86OSRingBell(int loudness, int pitch, int duration)
 
                 /* sleep a little to allow audio buffer to drain */
                 naptime = BELL_MS * i;
-                poll(NULL, 0, naptime);
+                xserver_poll(NULL, 0, naptime);
 
                 i = ((sizeof(samples) * iovcnt) - written) % sizeof(samples);
                 iovcnt = 0;
commit 711c36558f50943c8342f25ad210281134887a3d
Author: Brian M. Clapper <bmc at clapper.org>
Date:   Mon Jul 11 18:30:05 2016 -0400

    os: Add poll emulation for mingw [v2]
    
    v2: rename as 'xserver_poll' to avoid potential library name
        collisions. Provide 'xserver_poll.h' which uses the system
        poll where available and falls back to this emulation otherwise.
        Autodetects when this is required, building the emulation only
        then
    
    Source: https://github.com/bmc/poll
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 52466d1..58fcf79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -219,9 +219,10 @@ dnl Checks for library functions.
 AC_CHECK_FUNCS([backtrace ffs geteuid getuid issetugid getresuid \
 	getdtablesize getifaddrs getpeereid getpeerucred getprogname getzoneid \
 	mmap posix_fallocate seteuid shmctl64 strncasecmp vasprintf vsnprintf \
-	walkcontext setitimer])
+	walkcontext setitimer poll])
 AC_CONFIG_LIBOBJ_DIR([os])
 AC_REPLACE_FUNCS([reallocarray strcasecmp strcasestr strlcat strlcpy strndup])
+AM_CONDITIONAL(POLL, [test "x$ac_cv_func_poll" = "xyes"])
 
 AC_CHECK_DECLS([program_invocation_short_name], [], [], [[#include <errno.h>]])
 
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index fc7d1a1..bf2a9ed 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -527,4 +527,7 @@
 /* Use input thread */
 #undef INPUTTHREAD
 
+/* Have poll() */
+#undef HAVE_POLL
+
 #endif /* _DIX_CONFIG_H_ */
diff --git a/include/xserver_poll.h b/include/xserver_poll.h
new file mode 100644
index 0000000..110d30c
--- /dev/null
+++ b/include/xserver_poll.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2016 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _XSERVER_POLL_H_
+#define _XSERVER_POLL_H_
+
+#ifndef _DIX_CONFIG_H_
+#error must inclue dix-config.h to use xserver_poll.h
+#endif
+
+#if HAVE_POLL
+#include <poll.h>
+#define xserver_poll(fds, nfds, timeout) poll(fds, nfds, timeout)
+#else
+
+#define POLLIN		0x01
+#define POLLPRI		0x02
+#define POLLOUT		0x04
+#define POLLERR		0x08
+#define POLLHUP		0x10
+#define POLLNVAL	0x20
+
+struct pollfd
+{
+    int     fd;
+    short   events;
+    short   revents;
+};
+
+typedef unsigned long nfds_t;
+
+int xserver_poll (struct pollfd *pArray, nfds_t n_fds, int timeout);
+
+#endif
+
+#endif /* _XSERVER_POLL_H_ */
diff --git a/os/Makefile.am b/os/Makefile.am
index fc49a73..c449076 100644
--- a/os/Makefile.am
+++ b/os/Makefile.am
@@ -7,6 +7,8 @@ XDMCP_SRCS = xdmcp.c
 XORG_SRCS = log.c
 BUSFAULT_SRCS = busfault.c
 
+XSERVER_POLL_SRCS=xserver_poll.c
+
 libos_la_SOURCES = 	\
 	WaitFor.c	\
 	access.c	\
@@ -32,6 +34,11 @@ if SECURE_RPC
 libos_la_SOURCES += $(SECURERPC_SRCS)
 endif
 
+if POLL
+else
+libos_la_SOURCES += $(XSERVER_POLL_SRCS)
+endif
+
 if XDMCP
 libos_la_SOURCES += $(XDMCP_SRCS)
 endif
diff --git a/os/xserver_poll.c b/os/xserver_poll.c
new file mode 100644
index 0000000..f152cda
--- /dev/null
+++ b/os/xserver_poll.c
@@ -0,0 +1,277 @@
+/*---------------------------------------------------------------------------*\
+  $Id$
+
+  NAME
+
+	poll - select(2)-based poll() emulation function for BSD systems.
+
+  SYNOPSIS
+	#include "poll.h"
+
+	struct pollfd
+	{
+	    int     fd;
+	    short   events;
+	    short   revents;
+	}
+
+	int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
+
+  DESCRIPTION
+
+	This file, and the accompanying "poll.h", implement the System V
+	poll(2) system call for BSD systems (which typically do not provide
+	poll()).  Poll() provides a method for multiplexing input and output
+	on multiple open file descriptors; in traditional BSD systems, that
+	capability is provided by select().  While the semantics of select()
+	differ from those of poll(), poll() can be readily emulated in terms
+	of select() -- which is how this function is implemented.
+
+  REFERENCES
+	Stevens, W. Richard. Unix Network Programming.  Prentice-Hall, 1990.
+
+  NOTES
+	1. This software requires an ANSI C compiler.
+
+  LICENSE
+
+  This software is released under the following BSD license, adapted from
+  http://opensource.org/licenses/bsd-license.php
+
+  Copyright (c) 1995-2011, Brian M. Clapper
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+  * Neither the name of the clapper.org nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*\
+				 Includes
+\*---------------------------------------------------------------------------*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <unistd.h>			     /* standard Unix definitions */
+#include <sys/types.h>                       /* system types */
+#include <sys/time.h>                        /* time definitions */
+#include <assert.h>                          /* assertion macros */
+#include <string.h>                          /* string functions */
+#include "xserver_poll.h"
+
+/*---------------------------------------------------------------------------*\
+				  Macros
+\*---------------------------------------------------------------------------*/
+
+#ifndef MAX
+#define MAX(a,b)	((a) > (b) ? (a) : (b))
+#endif
+
+/*---------------------------------------------------------------------------*\
+			     Private Functions
+\*---------------------------------------------------------------------------*/
+
+static int map_poll_spec
+			(struct pollfd *pArray,
+                         nfds_t         n_fds,
+			  fd_set        *pReadSet,
+			  fd_set        *pWriteSet,
+			  fd_set        *pExceptSet)
+{
+    register nfds_t  i;                      /* loop control */
+    register struct  pollfd *pCur;           /* current array element */
+    register int     max_fd = -1;            /* return value */
+
+    /*
+       Map the poll() structures into the file descriptor sets required
+       by select().
+    */
+    for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
+    {
+        /* Skip any bad FDs in the array. */
+
+        if (pCur->fd < 0)
+            continue;
+
+	if (pCur->events & POLLIN)
+	{
+	    /* "Input Ready" notification desired. */
+	    FD_SET (pCur->fd, pReadSet);
+	}
+
+	if (pCur->events & POLLOUT)
+	{
+	    /* "Output Possible" notification desired. */
+	    FD_SET (pCur->fd, pWriteSet);
+	}
+
+	if (pCur->events & POLLPRI)
+	{
+	    /*
+	       "Exception Occurred" notification desired.  (Exceptions
+	       include out of band data.
+	    */
+	    FD_SET (pCur->fd, pExceptSet);
+	}
+
+	max_fd = MAX (max_fd, pCur->fd);
+    }
+
+    return max_fd;
+}
+
+static struct timeval *map_timeout
+			(int poll_timeout, struct timeval *pSelTimeout)
+{
+    struct timeval *pResult;
+
+    /*
+       Map the poll() timeout value into a select() timeout.  The possible
+       values of the poll() timeout value, and their meanings, are:
+
+       VALUE	MEANING
+
+       -1	wait indefinitely (until signal occurs)
+        0	return immediately, don't block
+       >0	wait specified number of milliseconds
+
+       select() uses a "struct timeval", which specifies the timeout in
+       seconds and microseconds, so the milliseconds value has to be mapped
+       accordingly.
+    */
+
+    assert (pSelTimeout != (struct timeval *) NULL);
+
+    switch (poll_timeout)
+    {
+	case -1:
+	    /*
+	       A NULL timeout structure tells select() to wait indefinitely.
+	    */
+	    pResult = (struct timeval *) NULL;
+	    break;
+
+	case 0:
+	    /*
+	       "Return immediately" (test) is specified by all zeros in
+	       a timeval structure.
+	    */
+	    pSelTimeout->tv_sec  = 0;
+	    pSelTimeout->tv_usec = 0;
+	    pResult = pSelTimeout;
+	    break;
+
+	default:
+	    /* Wait the specified number of milliseconds. */
+	    pSelTimeout->tv_sec  = poll_timeout / 1000; /* get seconds */
+	    poll_timeout        %= 1000;                /* remove seconds */
+	    pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */
+	    pResult = pSelTimeout;
+	    break;
+    }
+
+
+    return pResult;
+}
+
+static void map_select_results
+			 (struct pollfd *pArray,
+			  unsigned long  n_fds,
+			  fd_set        *pReadSet,
+			  fd_set        *pWriteSet,
+			  fd_set        *pExceptSet)
+{
+    register unsigned long  i;                   /* loop control */
+    register struct	    pollfd *pCur;        /* current array element */
+
+    for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
+    {
+        /* Skip any bad FDs in the array. */
+
+        if (pCur->fd < 0)
+            continue;
+
+	/* Exception events take priority over input events. */
+
+	pCur->revents = 0;
+	if (FD_ISSET (pCur->fd, pExceptSet))
+	    pCur->revents |= POLLPRI;
+
+	else if (FD_ISSET (pCur->fd, pReadSet))
+	    pCur->revents |= POLLIN;
+
+	if (FD_ISSET (pCur->fd, pWriteSet))
+	    pCur->revents |= POLLOUT;
+    }
+
+    return;
+}
+
+/*---------------------------------------------------------------------------*\
+			     Public Functions
+\*---------------------------------------------------------------------------*/
+
+int xserver_poll
+	(struct pollfd *pArray, unsigned long n_fds, int timeout)
+{
+    fd_set  read_descs;                          /* input file descs */
+    fd_set  write_descs;                         /* output file descs */
+    fd_set  except_descs;                        /* exception descs */
+    struct  timeval stime;                       /* select() timeout value */
+    int	    ready_descriptors;                   /* function result */
+    int	    max_fd;                              /* maximum fd value */
+    struct  timeval *pTimeout;                   /* actually passed */
+
+    FD_ZERO (&read_descs);
+    FD_ZERO (&write_descs);
+    FD_ZERO (&except_descs);
+
+    assert (pArray != (struct pollfd *) NULL);
+
+    /* Map the poll() file descriptor list in the select() data structures. */
+
+    max_fd = map_poll_spec (pArray, n_fds,
+			    &read_descs, &write_descs, &except_descs);
+
+    /* Map the poll() timeout value in the select() timeout structure. */
+
+    pTimeout = map_timeout (timeout, &stime);
+
+    /* Make the select() call. */
+
+    ready_descriptors = select (max_fd + 1, &read_descs, &write_descs,
+				&except_descs, pTimeout);
+
+    if (ready_descriptors >= 0)
+    {
+	map_select_results (pArray, n_fds,
+			    &read_descs, &write_descs, &except_descs);
+    }
+
+    return ready_descriptors;
+}


More information about the xorg-commit mailing list