xserver: Branch 'master' - 2 commits

Keith Packard keithp at kemper.freedesktop.org
Mon Aug 15 05:53:25 UTC 2016


 os/ospoll.c |   35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

New commits:
commit 67fc5d68f967d19236221b2c0c2e0fe45acf560f
Author: Keith Packard <keithp at keithp.com>
Date:   Sat Aug 13 09:02:15 2016 -0700

    os: Abandon loop after poll call when array of fds has changed
    
    If a file descriptor is added or removed from an ospoll callback, then
    the arrays containing file descriptor information will have all of
    their indices changed, so the loop state is no longer consistent. Just
    bail out and let the caller come back around to try again.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/os/ospoll.c b/os/ospoll.c
index 2996ac7..b00d422 100644
--- a/os/ospoll.c
+++ b/os/ospoll.c
@@ -82,6 +82,7 @@ struct ospoll {
     struct ospollfd     *osfds;
     int                 num;
     int                 size;
+    Bool                changed;
 };
 
 #endif
@@ -279,6 +280,7 @@ ospoll_add(struct ospoll *ospoll, int fd,
         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->changed = TRUE;
 
         ospoll->fds[pos].fd = fd;
         ospoll->fds[pos].events = 0;
@@ -316,6 +318,7 @@ ospoll_remove(struct ospoll *ospoll, int fd)
         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
         array_delete(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
         ospoll->num--;
+        ospoll->changed = TRUE;
 #endif
     }
 }
@@ -408,6 +411,7 @@ ospoll_wait(struct ospoll *ospoll, int timeout)
 #endif
 #if POLL
     nready = xserver_poll(ospoll->fds, ospoll->num, timeout);
+    ospoll->changed = FALSE;
     if (nready > 0) {
         int f;
         for (f = 0; f < ospoll->num; f++) {
@@ -427,6 +431,12 @@ ospoll_wait(struct ospoll *ospoll, int timeout)
                     xevents |= X_NOTIFY_ERROR;
                 ospoll->osfds[f].callback(ospoll->fds[f].fd, xevents,
                                           ospoll->osfds[f].data);
+
+                /* Check to see if the arrays have changed, and just go back
+                 * around again
+                 */
+                if (ospoll->changed)
+                    break;
             }
         }
     }
commit 7d6fffb6013cfc718d884cc549d7a8fef37240cf
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Aug 12 15:23:55 2016 -0700

    os: Delay freeing of epoll_wait return pointers until epoll is idle.
    
    Instead of freeing the struct ospollfd elements when the fd is
    removed by the user, delay that until epoll is idle so that we are
    sure no epoll_event structures could contain the stale pointer. This
    handles cases where an fd is removed from the ospoll callback
    interface, and also in case the OS keeps stale pointers around after
    the call to epoll_ctl with EPOLL_CTL_DEL.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/os/ospoll.c b/os/ospoll.c
index 3c2b80b..2996ac7 100644
--- a/os/ospoll.c
+++ b/os/ospoll.c
@@ -54,6 +54,7 @@ struct ospollfd {
     enum ospoll_trigger trigger;
     void                (*callback)(int fd, int xevents, void *data);
     void                *data;
+    struct xorg_list    deleted;
 };
 
 struct ospoll {
@@ -61,6 +62,7 @@ struct ospoll {
     struct ospollfd     **fds;
     int                 num;
     int                 size;
+    struct xorg_list    deleted;
 };
 
 #endif
@@ -115,6 +117,19 @@ ospoll_find(struct ospoll *ospoll, int fd)
     return -(lo + 1);
 }
 
+#if EPOLL
+static void
+ospoll_clean_deleted(struct ospoll *ospoll)
+{
+    struct ospollfd     *osfd, *tmp;
+
+    xorg_list_for_each_entry_safe(osfd, tmp, &ospoll->deleted, deleted) {
+        xorg_list_del(&osfd->deleted);
+        free(osfd);
+    }
+}
+#endif
+
 /* Insert an element into an array
  *
  * base: base address of array
@@ -160,6 +175,7 @@ ospoll_create(void)
         free (ospoll);
         return NULL;
     }
+    xorg_list_init(&ospoll->deleted);
     return ospoll;
 #endif
 #if POLL
@@ -174,6 +190,7 @@ ospoll_destroy(struct ospoll *ospoll)
     if (ospoll) {
         assert (ospoll->num == 0);
         close(ospoll->epoll_fd);
+        ospoll_clean_deleted(ospoll);
         free(ospoll->fds);
         free(ospoll);
     }
@@ -291,7 +308,9 @@ ospoll_remove(struct ospoll *ospoll, int fd)
 
         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
         ospoll->num--;
-        free (osfd);
+        osfd->callback = NULL;
+        osfd->data = NULL;
+        xorg_list_add(&osfd->deleted, &ospoll->deleted);
 #endif
 #if POLL
         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
@@ -382,8 +401,10 @@ ospoll_wait(struct ospoll *ospoll, int timeout)
         if (revents & (~(EPOLLIN|EPOLLOUT)))
             xevents |= X_NOTIFY_ERROR;
 
-        osfd->callback(osfd->fd, xevents, osfd->data);
+        if (osfd->callback)
+            osfd->callback(osfd->fd, xevents, osfd->data);
     }
+    ospoll_clean_deleted(ospoll);
 #endif
 #if POLL
     nready = xserver_poll(ospoll->fds, ospoll->num, timeout);


More information about the xorg-commit mailing list