From af1db55aa5b69652fb76c704a806c4395607b9b1 Mon Sep 17 00:00:00 2001 From: Tomoya Fujita Date: Mon, 18 May 2026 15:41:18 +0900 Subject: [PATCH 1/2] address unsafe list mutation during iteration and bypasses exception re-raise. Signed-off-by: Tomoya Fujita --- rclpy/rclpy/executors.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rclpy/rclpy/executors.py b/rclpy/rclpy/executors.py index d03d770d6..656a79237 100644 --- a/rclpy/rclpy/executors.py +++ b/rclpy/rclpy/executors.py @@ -435,8 +435,7 @@ def spin_until_future_complete( now = time.monotonic() if now >= end: - self._exit_spin() - return + break timeout_left.timeout = end - now finally: @@ -1109,10 +1108,10 @@ def _spin_once_impl( self._executor.submit(handler) self._futures.append(handler) with self._futures_lock: - for future in self._futures: - if future.done(): - self._futures.remove(future) - future.result() # raise any exceptions + done_futures = [f for f in self._futures if f.done()] + for future in done_futures: + self._futures.remove(future) + future.result() # raise any exceptions # Yield GIL so executor threads have a chance to run. os.sched_yield() if hasattr(os, 'sched_yield') else time.sleep(0) From e71758a0056f5e28e24122acb63e8033969574cc Mon Sep 17 00:00:00 2001 From: Tomoya Fujita Date: Wed, 20 May 2026 14:10:05 +0900 Subject: [PATCH 2/2] cover cancelled future along with done ones. Signed-off-by: Tomoya Fujita --- rclpy/rclpy/executors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rclpy/rclpy/executors.py b/rclpy/rclpy/executors.py index 656a79237..713a67911 100644 --- a/rclpy/rclpy/executors.py +++ b/rclpy/rclpy/executors.py @@ -1108,7 +1108,7 @@ def _spin_once_impl( self._executor.submit(handler) self._futures.append(handler) with self._futures_lock: - done_futures = [f for f in self._futures if f.done()] + done_futures = [f for f in self._futures if f.done() or f.cancelled()] for future in done_futures: self._futures.remove(future) future.result() # raise any exceptions