Fix: common: poll: compat_poll_wait never finishes
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 16 Oct 2020 18:43:39 +0000 (14:43 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 27 Oct 2020 21:25:23 +0000 (17:25 -0400)
compat_poll_wait hangs when poll returns an array of file
descriptors of the form:
  [ Inactive Active ]

The logic to find the first idle pollfd entry is bogus and actually
skips the first idle entry. This causes the follow-up loop to never
conclude.

The pollfd array defragmentation logic is re-written in a simpler
style to handle those cases appropriately.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I8669a870df1ec1160f05e35e83671917bb80d6f9

src/common/compat/poll.c

index d9acd901c0382802c136d49d9fa4a32eba22b24e..c5dd494b8920317140eb44afbd9f37e52b936e24 100644 (file)
@@ -632,8 +632,7 @@ int compat_poll_wait(struct lttng_poll_event *events, int timeout,
                bool interruptible)
 {
        int ret, active_fd_count;
-       int idle_pfd_index = 0;
-       size_t i;
+       size_t pos = 0, consecutive_entries = 0, non_idle_pos;
 
        if (events == NULL || events->current.events == NULL) {
                ERR("poll wait arguments error");
@@ -668,34 +667,36 @@ int compat_poll_wait(struct lttng_poll_event *events, int timeout,
        active_fd_count = ret;
 
        /*
-        * Swap all active pollfd structs to the beginning of the
-        * array to emulate compat-epoll behaviour. This algorithm takes
-        * advantage of poll's returned value and the burst nature of active
-        * events on the file descriptors. The while loop guarantees that
-        * idle_pfd will always point to an idle fd.
+        * Move all active pollfd structs to the beginning of the
+        * array to emulate compat-epoll behaviour.
         */
        if (active_fd_count == events->wait.nb_fd) {
                goto end;
        }
-       while (idle_pfd_index < active_fd_count &&
-                       events->wait.events[idle_pfd_index].revents != 0) {
-               idle_pfd_index++;
-       }
 
-       for (i = idle_pfd_index + 1; idle_pfd_index < active_fd_count;
-                       i++) {
-               struct pollfd swap_pfd;
-               struct pollfd *idle_pfd = &events->wait.events[idle_pfd_index];
-               struct pollfd *current_pfd = &events->wait.events[i];
+       while (consecutive_entries != active_fd_count) {
+               struct pollfd *current = &events->wait.events[pos];
+               struct pollfd idle_entry;
 
-               if (idle_pfd->revents != 0) {
-                       swap_pfd = *current_pfd;
-                       *current_pfd = *idle_pfd;
-                       *idle_pfd = swap_pfd;
-                       idle_pfd_index++;
+               if (current->revents != 0) {
+                       consecutive_entries++;
+                       pos++;
+                       continue;
                }
-       }
 
+               non_idle_pos = pos;
+
+               /* Look for next non-idle entry. */
+               while (events->wait.events[++non_idle_pos].revents == 0);
+
+               /* Swap idle and non-idle entries. */
+               idle_entry = *current;
+               *current = events->wait.events[non_idle_pos];
+               events->wait.events[non_idle_pos] = idle_entry;
+
+               consecutive_entries++;
+               pos++;
+       }
 end:
        return ret;
 
This page took 0.02677 seconds and 4 git commands to generate.