[PATCH xserver 1/2] os: Delay freeing of epoll_wait return pointers until epoll is idle.

Keith Packard keithp at keithp.com
Sat Aug 13 16:11:17 UTC 2016


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>
---
 os/ospoll.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

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);
-- 
2.8.1



More information about the xorg-devel mailing list