Compare commits

...

3 Commits

Author SHA1 Message Date
Tomoya Fujita
5d54ee5baa make sure promise/future is reset for next incoming signal.
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-11-21 16:16:00 +09:00
Tomoya Fujita
12d777293c address uncrustify warnings.
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-11-21 15:36:20 +09:00
Tomoya Fujita
fee3bb1668 use std::future for signal synchronization for cross-platform.
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-11-21 15:30:07 +09:00
2 changed files with 40 additions and 92 deletions

View File

@@ -16,19 +16,11 @@
#include <atomic>
#include <csignal>
#include <future>
#include <mutex>
#include <string>
#include <thread>
// includes for semaphore notification code
#if defined(_WIN32)
#include <windows.h>
#elif defined(__APPLE__)
#include <dispatch/dispatch.h>
#else // posix
#include <semaphore.h>
#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<std::promise<void>>();
signal_future_ = std::make_unique<std::future<void>>(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<void> future_to_wait;
{
std::lock_guard<std::mutex> 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<std::mutex> lock(signal_mutex_);
signal_promise_ = std::make_unique<std::promise<void>>();
signal_future_ = std::make_unique<std::future<void>>(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());
try {
std::lock_guard<std::mutex> 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
}
#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()");
}
#endif
}
rclcpp::SignalHandlerOptions

View File

@@ -17,21 +17,14 @@
#include <atomic>
#include <csignal>
#include <future>
#include <memory>
#include <mutex>
#include <thread>
#include "rclcpp/logging.hpp"
#include "rclcpp/utilities.hpp"
// includes for semaphore notification code
#if defined(_WIN32)
#include <windows.h>
#elif defined(__APPLE__)
#include <dispatch/dispatch.h>
#else // posix
#include <semaphore.h>
#endif
// Determine if sigaction is available
#if __APPLE__ || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
#define RCLCPP_HAS_SIGACTION
@@ -199,14 +192,9 @@ private:
// 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<std::promise<void>> signal_promise_;
std::unique_ptr<std::future<void>> signal_future_;
};
} // namespace rclcpp