Refine neighbourhood reassignment
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c
index fcccccc..99e4441 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.c
+++ b/src/core/lib/iomgr/ev_epoll1_linux.c
@@ -117,6 +117,7 @@
 struct grpc_pollset {
   gpr_mu mu;
   pollset_neighbourhood *neighbourhood;
+  bool reassigning_neighbourhood;
   grpc_pollset_worker *root_worker;
   bool kicked_without_poller;
   bool seen_inactive;
@@ -394,20 +395,33 @@
   *mu = &pollset->mu;
   pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
   pollset->seen_inactive = true;
-  pollset->next = pollset->prev = pollset;
 }
 
 static void pollset_destroy(grpc_pollset *pollset) {
+  gpr_mu_lock(&pollset->mu);
   if (!pollset->seen_inactive) {
-    gpr_mu_lock(&pollset->neighbourhood->mu);
-    pollset->prev->next = pollset->next;
-    pollset->next->prev = pollset->prev;
-    if (pollset == pollset->neighbourhood->active_root) {
-      pollset->neighbourhood->active_root =
-          pollset->next == pollset ? NULL : pollset->next;
+    pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
+    gpr_mu_unlock(&pollset->mu);
+retry_lock_neighbourhood:
+    gpr_mu_lock(&neighbourhood->mu);
+    gpr_mu_lock(&pollset->mu);
+    if (!pollset->seen_inactive) {
+      if (pollset->neighbourhood != neighbourhood) {
+        gpr_mu_unlock(&neighbourhood->mu);
+        neighbourhood = pollset->neighbourhood;
+        gpr_mu_unlock(&pollset->mu);
+        goto retry_lock_neighbourhood;
+      }
+      pollset->prev->next = pollset->next;
+      pollset->next->prev = pollset->prev;
+      if (pollset == pollset->neighbourhood->active_root) {
+        pollset->neighbourhood->active_root =
+            pollset->next == pollset ? NULL : pollset->next;
+      }
     }
     gpr_mu_unlock(&pollset->neighbourhood->mu);
   }
+  gpr_mu_unlock(&pollset->mu);
   gpr_mu_destroy(&pollset->mu);
 }
 
@@ -543,8 +557,13 @@
   if (pollset->seen_inactive) {
     // pollset has been observed to be inactive, we need to move back to the
     // active list
-    pollset_neighbourhood *neighbourhood = pollset->neighbourhood =
-        &g_neighbourhoods[choose_neighbourhood()];
+    bool is_reassigning = false;
+    if (!pollset->reassigning_neighbourhood) {
+      is_reassigning = true;
+      pollset->reassigning_neighbourhood = true;
+      pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
+    }
+    pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
     gpr_mu_unlock(&pollset->mu);
   // pollset unlocked: state may change (even worker->kick_state)
   retry_lock_neighbourhood:
@@ -569,6 +588,10 @@
         pollset->next->prev = pollset->prev->next = pollset;
       }
     }
+    if (is_reassigning) {
+      GPR_ASSERT(pollset->reassigning_neighbourhood);
+      pollset->reassigning_neighbourhood = false;
+    }
     gpr_mu_unlock(&neighbourhood->mu);
   }
   worker_insert(pollset, worker);
@@ -629,14 +652,11 @@
     if (!found_worker) {
       inspect->seen_inactive = true;
       if (inspect == neighbourhood->active_root) {
-        if (inspect->next == neighbourhood->active_root) {
-          neighbourhood->active_root = NULL;
-        } else {
-          neighbourhood->active_root = inspect->next;
-        }
+          neighbourhood->active_root = inspect->next == inspect ? NULL : inspect->next;
       }
       inspect->next->prev = inspect->prev;
       inspect->prev->next = inspect->next;
+      inspect->next = inspect->prev = NULL;
     }
     gpr_mu_unlock(&inspect->mu);
   } while (!found_worker);