From 870edc8d277af5d73eceae520f60303524187dcf Mon Sep 17 00:00:00 2001 From: Roger Strain Date: Mon, 18 Nov 2019 14:25:14 +0000 Subject: [PATCH] Only check for new work once in spin_some (#471) To prevent the Executor::spin_some() method for potentially running indefinitely long, a flag only allows the method which loads new work to execute once per cycle. Distribution Statement A; OPSEC #2893 Signed-off-by: Roger Strain --- rclcpp/include/rclcpp/executor.hpp | 3 ++- rclcpp/src/rclcpp/executor.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rclcpp/include/rclcpp/executor.hpp b/rclcpp/include/rclcpp/executor.hpp index cbeda82a24..30c0ee0a7f 100644 --- a/rclcpp/include/rclcpp/executor.hpp +++ b/rclcpp/include/rclcpp/executor.hpp @@ -337,7 +337,8 @@ class Executor bool get_next_executable( AnyExecutable & any_executable, - std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1)); + std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1), + bool allow_new_work = true); /// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins. std::atomic_bool spinning; diff --git a/rclcpp/src/rclcpp/executor.cpp b/rclcpp/src/rclcpp/executor.cpp index c8ee23752b..c49c5f6009 100644 --- a/rclcpp/src/rclcpp/executor.cpp +++ b/rclcpp/src/rclcpp/executor.cpp @@ -234,13 +234,15 @@ Executor::spin_some(std::chrono::nanoseconds max_duration) throw std::runtime_error("spin_some() called while already spinning"); } RCLCPP_SCOPE_EXIT(this->spinning.store(false); ); + bool allow_new_work = true; while (spinning.load() && max_duration_not_elapsed()) { AnyExecutable any_exec; - if (get_next_executable(any_exec, std::chrono::milliseconds::zero())) { + if (get_next_executable(any_exec, std::chrono::milliseconds::zero(), allow_new_work)) { execute_any_executable(any_exec); } else { break; } + allow_new_work = false; } } @@ -561,14 +563,14 @@ Executor::get_next_ready_executable(AnyExecutable & any_executable) } bool -Executor::get_next_executable(AnyExecutable & any_executable, std::chrono::nanoseconds timeout) +Executor::get_next_executable(AnyExecutable & any_executable, std::chrono::nanoseconds timeout, bool allow_new_work) { bool success = false; // Check to see if there are any subscriptions or timers needing service // TODO(wjwwood): improve run to run efficiency of this function success = get_next_ready_executable(any_executable); // If there are none - if (!success) { + if (!success && allow_new_work) { // Wait for subscriptions or timers to work on wait_for_work(timeout); if (!spinning.load()) {