diff --git a/rclcpp/src/rclcpp/signal_handler.cpp b/rclcpp/src/rclcpp/signal_handler.cpp index cf26d06df4..21f7fbd83c 100644 --- a/rclcpp/src/rclcpp/signal_handler.cpp +++ b/rclcpp/src/rclcpp/signal_handler.cpp @@ -16,19 +16,11 @@ #include #include +#include #include #include #include -// includes for semaphore notification code -#if defined(_WIN32) -#include -#elif defined(__APPLE__) -#include -#else // posix -#include -#endif - #include "rclcpp/logging.hpp" #include "rclcpp/utilities.hpp" #include "rcutils/strerror.h" @@ -287,22 +279,8 @@ SignalHandler::deferred_signal_handler() void SignalHandler::setup_wait_for_signal() { -#if defined(_WIN32) - signal_handler_sem_ = CreateSemaphore( - NULL, // default security attributes - 0, // initial semaphore count - 1, // maximum semaphore count - NULL); // unnamed semaphore - if (NULL == signal_handler_sem_) { - throw std::runtime_error("CreateSemaphore() failed in setup_wait_for_signal()"); - } -#elif defined(__APPLE__) - signal_handler_sem_ = dispatch_semaphore_create(0); -#else // posix - if (-1 == sem_init(&signal_handler_sem_, 0, 0)) { - throw std::runtime_error(std::string("sem_init() failed: ") + strerror(errno)); - } -#endif + signal_promise_ = std::make_unique>(); + signal_future_ = std::make_unique>(signal_promise_->get_future()); wait_for_signal_is_setup_.store(true); } @@ -312,15 +290,8 @@ SignalHandler::teardown_wait_for_signal() noexcept if (!wait_for_signal_is_setup_.exchange(false)) { return; } -#if defined(_WIN32) - CloseHandle(signal_handler_sem_); -#elif defined(__APPLE__) - dispatch_release(signal_handler_sem_); -#else // posix - if (-1 == sem_destroy(&signal_handler_sem_)) { - RCLCPP_ERROR(get_logger(), "invalid semaphore in teardown_wait_for_signal()"); - } -#endif + signal_promise_.reset(); + signal_future_.reset(); } void @@ -330,37 +301,27 @@ SignalHandler::wait_for_signal() RCLCPP_ERROR(get_logger(), "called wait_for_signal() before setup_wait_for_signal()"); return; } -#if defined(_WIN32) - DWORD dw_wait_result = WaitForSingleObject(signal_handler_sem_, INFINITE); - switch (dw_wait_result) { - case WAIT_ABANDONED: - RCLCPP_ERROR( - get_logger(), "WaitForSingleObject() failed in wait_for_signal() with WAIT_ABANDONED: %s", - GetLastError()); - break; - case WAIT_OBJECT_0: - // successful - break; - case WAIT_TIMEOUT: - RCLCPP_ERROR(get_logger(), "WaitForSingleObject() timedout out in wait_for_signal()"); - break; - case WAIT_FAILED: - RCLCPP_ERROR( - get_logger(), "WaitForSingleObject() failed in wait_for_signal(): %s", GetLastError()); - break; - default: - RCLCPP_ERROR( - get_logger(), "WaitForSingleObject() gave unknown return in wait_for_signal(): %s", - GetLastError()); + + std::shared_future future_to_wait; + { + std::lock_guard lock(signal_mutex_); + future_to_wait = signal_future_->share(); + } + + try { + // Wait for the future to be signaled + future_to_wait.wait(); + + // After being signaled, create a new promise/future pair for the next signal + // This allows multiple signals to be handled properly + { + std::lock_guard lock(signal_mutex_); + signal_promise_ = std::make_unique>(); + signal_future_ = std::make_unique>(signal_promise_->get_future()); + } + } catch (const std::future_error & e) { + RCLCPP_ERROR(get_logger(), "future_error in wait_for_signal(): %s", e.what()); } -#elif defined(__APPLE__) - dispatch_semaphore_wait(signal_handler_sem_, DISPATCH_TIME_FOREVER); -#else // posix - int s; - do { - s = sem_wait(&signal_handler_sem_); - } while (-1 == s && EINTR == errno); -#endif } void @@ -369,18 +330,17 @@ SignalHandler::notify_signal_handler() noexcept if (!wait_for_signal_is_setup_.load()) { return; } -#if defined(_WIN32) - if (!ReleaseSemaphore(signal_handler_sem_, 1, NULL)) { - RCLCPP_ERROR( - get_logger(), "ReleaseSemaphore() failed in notify_signal_handler(): %s", GetLastError()); - } -#elif defined(__APPLE__) - dispatch_semaphore_signal(signal_handler_sem_); -#else // posix - if (-1 == sem_post(&signal_handler_sem_)) { - RCLCPP_ERROR(get_logger(), "sem_post failed in notify_signal_handler()"); + + try { + std::lock_guard lock(signal_mutex_); + // Set the promise value to unblock the waiting future + if (signal_promise_) { + signal_promise_->set_value(); + } + } catch (const std::future_error &) { + // Promise may already be set - this is expected on subsequent signals + // No error logging needed as this is normal behavior } -#endif } rclcpp::SignalHandlerOptions diff --git a/rclcpp/src/rclcpp/signal_handler.hpp b/rclcpp/src/rclcpp/signal_handler.hpp index db608b0d10..e383a62113 100644 --- a/rclcpp/src/rclcpp/signal_handler.hpp +++ b/rclcpp/src/rclcpp/signal_handler.hpp @@ -17,21 +17,14 @@ #include #include +#include +#include #include #include #include "rclcpp/logging.hpp" #include "rclcpp/utilities.hpp" -// includes for semaphore notification code -#if defined(_WIN32) -#include -#elif defined(__APPLE__) -#include -#else // posix -#include -#endif - // Determine if sigaction is available #if __APPLE__ || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE #define RCLCPP_HAS_SIGACTION @@ -199,14 +192,9 @@ class SignalHandler final // Whether or not the semaphore for wait_for_signal is setup. std::atomic_bool wait_for_signal_is_setup_; - // Storage for the wait_for_signal semaphore. -#if defined(_WIN32) - HANDLE signal_handler_sem_; -#elif defined(__APPLE__) - dispatch_semaphore_t signal_handler_sem_; -#else // posix - sem_t signal_handler_sem_; -#endif + std::mutex signal_mutex_; + std::unique_ptr> signal_promise_; + std::unique_ptr> signal_future_; }; } // namespace rclcpp