From 2e58dde5efbe9fa99337889e4a6d21b860c46cde Mon Sep 17 00:00:00 2001 From: William Woodall Date: Wed, 12 Dec 2018 21:12:49 -0800 Subject: [PATCH] use signal safe synchronization with platform specific semaphores (#607) * use signal safe synchronization with platform specific semaphores Signed-off-by: William Woodall * addressed feedback and refactored into separate files Signed-off-by: William Woodall * Apply suggestions from code review Co-Authored-By: wjwwood * include what you use (cpplint) Signed-off-by: William Woodall * avoid redundant use of SignalHandler:: Signed-off-by: William Woodall * Update rclcpp/src/rclcpp/signal_handler.hpp Co-Authored-By: wjwwood * fix Windows build Signed-off-by: William Woodall * actually fix Windows Signed-off-by: William Woodall --- rclcpp/CMakeLists.txt | 1 + rclcpp/src/rclcpp/signal_handler.cpp | 357 +++++++++++++++++++++++++++ rclcpp/src/rclcpp/signal_handler.hpp | 189 ++++++++++++++ rclcpp/src/rclcpp/utilities.cpp | 265 +------------------- 4 files changed, 548 insertions(+), 264 deletions(-) create mode 100644 rclcpp/src/rclcpp/signal_handler.cpp create mode 100644 rclcpp/src/rclcpp/signal_handler.hpp diff --git a/rclcpp/CMakeLists.txt b/rclcpp/CMakeLists.txt index 6c3bf88..e92117e 100644 --- a/rclcpp/CMakeLists.txt +++ b/rclcpp/CMakeLists.txt @@ -65,6 +65,7 @@ set(${PROJECT_NAME}_SRCS src/rclcpp/parameter_service.cpp src/rclcpp/publisher.cpp src/rclcpp/service.cpp + src/rclcpp/signal_handler.cpp src/rclcpp/subscription.cpp src/rclcpp/time.cpp src/rclcpp/time_source.cpp diff --git a/rclcpp/src/rclcpp/signal_handler.cpp b/rclcpp/src/rclcpp/signal_handler.cpp new file mode 100644 index 0000000..debad74 --- /dev/null +++ b/rclcpp/src/rclcpp/signal_handler.cpp @@ -0,0 +1,357 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "./signal_handler.hpp" + +#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 "rmw/impl/cpp/demangle.hpp" + +using rclcpp::SignalHandler; + +// initialize static storage in SignalHandler class +SignalHandler::signal_handler_type SignalHandler::old_signal_handler_; +std::atomic_bool SignalHandler::signal_received_ = ATOMIC_VAR_INIT(false); +std::atomic_bool SignalHandler::wait_for_signal_is_setup_ = ATOMIC_VAR_INIT(false); +#if defined(_WIN32) +HANDLE SignalHandler::signal_handler_sem_; +#elif defined(__APPLE__) +dispatch_semaphore_t SignalHandler::signal_handler_sem_; +#else // posix +sem_t SignalHandler::signal_handler_sem_; +#endif + +SignalHandler & +SignalHandler::get_global_signal_handler() +{ + static SignalHandler signal_handler; + return signal_handler; +} + +rclcpp::Logger & +SignalHandler::get_logger() +{ + static rclcpp::Logger logger = rclcpp::get_logger("rclcpp"); + return logger; +} + +bool +SignalHandler::install() +{ + std::lock_guard lock(install_mutex_); + bool already_installed = installed_.exchange(true); + if (already_installed) { + return false; + } + try { + setup_wait_for_signal(); + signal_received_.store(false); + + SignalHandler::signal_handler_type signal_handler_argument; +#if defined(RCLCPP_HAS_SIGACTION) + memset(&signal_handler_argument, 0, sizeof(signal_handler_argument)); + sigemptyset(&signal_handler_argument.sa_mask); + signal_handler_argument.sa_sigaction = signal_handler; + signal_handler_argument.sa_flags = SA_SIGINFO; +#else + signal_handler_argument = signal_handler; +#endif + + old_signal_handler_ = SignalHandler::set_signal_handler(SIGINT, signal_handler_argument); + + signal_handler_thread_ = std::thread(&SignalHandler::deferred_signal_handler, this); + } catch (...) { + installed_.store(false); + throw; + } + RCLCPP_DEBUG(get_logger(), "signal handler installed"); + return true; +} + +bool +SignalHandler::uninstall() +{ + std::lock_guard lock(install_mutex_); + bool installed = installed_.exchange(false); + if (!installed) { + return false; + } + try { + // TODO(wjwwood): what happens if someone overrides our signal handler then calls uninstall? + // I think we need to assert that we're the current signal handler, and mitigate if not. + set_signal_handler(SIGINT, old_signal_handler_); + RCLCPP_DEBUG(get_logger(), "SignalHandler::uninstall(): notifying deferred signal handler"); + notify_signal_handler(); + signal_handler_thread_.join(); + teardown_wait_for_signal(); + } catch (...) { + installed_.exchange(true); + throw; + } + RCLCPP_DEBUG(get_logger(), "signal handler uninstalled"); + return true; +} + +bool +SignalHandler::is_installed() +{ + return installed_.load(); +} + +SignalHandler::~SignalHandler() +{ + try { + uninstall(); + } catch (const std::exception & exc) { + RCLCPP_ERROR( + get_logger(), + "caught %s exception when uninstalling the sigint handler in rclcpp::~SignalHandler: %s", + rmw::impl::cpp::demangle(exc).c_str(), exc.what()); + } catch (...) { + RCLCPP_ERROR( + get_logger(), + "caught unknown exception when uninstalling the sigint handler in rclcpp::~SignalHandler"); + } +} + +RCLCPP_LOCAL +void +__safe_strerror(int errnum, char * buffer, size_t buffer_length) +{ +#if defined(_WIN32) + strerror_s(buffer, buffer_length, errnum); +#elif (defined(_GNU_SOURCE) && !defined(ANDROID)) + char * msg = strerror_r(errnum, buffer, buffer_length); + if (msg != buffer) { + strncpy(buffer, msg, buffer_length); + buffer[buffer_length - 1] = '\0'; + } +#else + int error_status = strerror_r(errnum, buffer, buffer_length); + if (error_status != 0) { + throw std::runtime_error("Failed to get error string for errno: " + std::to_string(errnum)); + } +#endif +} + +SignalHandler::signal_handler_type +SignalHandler::set_signal_handler( + int signal_value, + const SignalHandler::signal_handler_type & signal_handler) +{ + bool signal_handler_install_failed; + SignalHandler::signal_handler_type old_signal_handler; +#if defined(RCLCPP_HAS_SIGACTION) + ssize_t ret = sigaction(signal_value, &signal_handler, &old_signal_handler); + signal_handler_install_failed = (ret == -1); +#else + old_signal_handler = std::signal(signal_value, signal_handler); + signal_handler_install_failed = (old_signal_handler == SIG_ERR); +#endif + if (signal_handler_install_failed) { + char error_string[1024]; + __safe_strerror(errno, error_string, sizeof(error_string)); + auto msg = + "Failed to set SIGINT signal handler (" + std::to_string(errno) + "): " + error_string; + throw std::runtime_error(msg); + } + + return old_signal_handler; +} + +void +SignalHandler::signal_handler_common() +{ + signal_received_.store(true); + RCLCPP_DEBUG( + get_logger(), + "signal_handler(): SIGINT received, notifying deferred signal handler"); + notify_signal_handler(); +} + +#if defined(RCLCPP_HAS_SIGACTION) +void +SignalHandler::signal_handler(int signal_value, siginfo_t * siginfo, void * context) +{ + RCLCPP_INFO(get_logger(), "signal_handler(signal_value=%d)", signal_value); + + if (old_signal_handler_.sa_flags & SA_SIGINFO) { + if (old_signal_handler_.sa_sigaction != NULL) { + old_signal_handler_.sa_sigaction(signal_value, siginfo, context); + } + } else { + if ( + old_signal_handler_.sa_handler != NULL && // Is set + old_signal_handler_.sa_handler != SIG_DFL && // Is not default + old_signal_handler_.sa_handler != SIG_IGN) // Is not ignored + { + old_signal_handler_.sa_handler(signal_value); + } + } + + signal_handler_common(); +} +#else +void +SignalHandler::signal_handler(int signal_value) +{ + RCLCPP_INFO(get_logger(), "signal_handler(signal_value=%d)", signal_value); + + if (old_signal_handler_) { + old_signal_handler_(signal_value); + } + + signal_handler_common(); +} +#endif + +void +SignalHandler::deferred_signal_handler() +{ + while (true) { + if (signal_received_.exchange(false)) { + RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): SIGINT received, shutting down"); + for (auto context_ptr : rclcpp::get_contexts()) { + if (context_ptr->get_init_options().shutdown_on_sigint) { + RCLCPP_DEBUG( + get_logger(), + "deferred_signal_handler(): " + "shutting down rclcpp::Context @ %p, because it had shutdown_on_sigint == true", + context_ptr.get()); + context_ptr->shutdown("signal handler"); + } + } + } + if (!is_installed()) { + RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): signal handling uninstalled"); + break; + } + RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): waiting for SIGINT or uninstall"); + wait_for_signal(); + RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): woken up due to SIGINT or uninstall"); + } +} + +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 + wait_for_signal_is_setup_.store(true); +} + +void +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 +} + +void +SignalHandler::wait_for_signal() +{ + if (!wait_for_signal_is_setup_.load()) { + 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()); + } +#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 +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()"); + } +#endif +} diff --git a/rclcpp/src/rclcpp/signal_handler.hpp b/rclcpp/src/rclcpp/signal_handler.hpp new file mode 100644 index 0000000..81cb6e1 --- /dev/null +++ b/rclcpp/src/rclcpp/signal_handler.hpp @@ -0,0 +1,189 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef RCLCPP__SIGNAL_HANDLER_HPP_ +#define RCLCPP__SIGNAL_HANDLER_HPP_ + +#include +#include +#include +#include + +#include "rclcpp/logging.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 +#endif + +namespace rclcpp +{ + +/// Responsible for manaaging the SIGINT signal handling. +/** + * This class is responsible for: + * + * - installing the signal handler for SIGINT + * - uninstalling the signal handler for SIGINT + * - creating a thread to execute "on sigint" work outside of the signal handler + * - safely notifying the dedicated signal handling thread when receiving SIGINT + * - implementation of all of the signal handling work, like shutting down contexts + * + * \internal + */ +class SignalHandler final +{ +public: + /// Return the global singleton of this class. + static + SignalHandler & + get_global_signal_handler(); + + /// Return a global singleton logger to avoid needing to create it everywhere. + static + rclcpp::Logger & + get_logger(); + + /// Install the signal handler for SIGINT and start the dedicated signal handling thread. + /** + * Also stores the current signal handler to be called on SIGINT and to + * restore when uninstalling this signal handler. + */ + bool + install(); + + /// Uninstall the signal handler for SIGINT and join the dedicated singal handling thread. + /** + * Also restores the previous signal handler. + */ + bool + uninstall(); + + /// Return true if installed, false otherwise. + bool + is_installed(); + +private: + SignalHandler() = default; + + ~SignalHandler(); + +#if defined(RCLCPP_HAS_SIGACTION) + using signal_handler_type = struct sigaction; +#else + using signal_handler_type = void (*)(int); +#endif + // POSIX signal handler structure storage for the existing signal handler. + static SignalHandler::signal_handler_type old_signal_handler_; + + /// Set the signal handler function. + static + SignalHandler::signal_handler_type + set_signal_handler(int signal_value, const SignalHandler::signal_handler_type & signal_handler); + + /// Common signal handler code between sigaction and non-sigaction versions. + static + void + signal_handler_common(); + +#if defined(RCLCPP_HAS_SIGACTION) + /// Signal handler function. + static + void + signal_handler(int signal_value, siginfo_t * siginfo, void * context); +#else + /// Signal handler function. + static + void + signal_handler(int signal_value); +#endif + + /// Target of the dedicated signal handling thread. + void + deferred_signal_handler(); + + /// Setup anything that is necessary for wait_for_signal() or notify_signal_handler(). + /** + * This must be called before wait_for_signal() or notify_signal_handler(). + * This is not thread-safe. + */ + static + void + setup_wait_for_signal(); + + /// Undo all setup done in setup_wait_for_signal(). + /** + * Must not call wait_for_signal() or notify_signal_handler() after calling this. + * + * This is not thread-safe. + */ + static + void + teardown_wait_for_signal() noexcept; + + /// Wait for a notification from notify_signal_handler() in a signal safe way. + /** + * This static method may throw if posting the semaphore fails. + * + * This is not thread-safe. + */ + static + void + wait_for_signal(); + + /// Notify blocking wait_for_signal() calls in a signal safe way. + /** + * This is used to notify the deferred_signal_handler() thread to start work + * from the signal handler. + * + * This is thread-safe. + */ + static + void + notify_signal_handler() noexcept; + + // Whether or not a signal has been received. + static std::atomic_bool signal_received_; + // A thread to which singal handling tasks are deferred. + std::thread signal_handler_thread_; + + // A mutex used to synchronize the install() and uninstall() methods. + std::mutex install_mutex_; + // Whether or not the signal handler has been installed. + std::atomic_bool installed_{false}; + + // Whether or not the semaphore for wait_for_signal is setup. + static std::atomic_bool wait_for_signal_is_setup_; + // Storage for the wait_for_signal semaphore. +#if defined(_WIN32) + static HANDLE signal_handler_sem_; +#elif defined(__APPLE__) + static dispatch_semaphore_t signal_handler_sem_; +#else // posix + static sem_t signal_handler_sem_; +#endif +}; + +} // namespace rclcpp + +#endif // RCLCPP__SIGNAL_HANDLER_HPP_ diff --git a/rclcpp/src/rclcpp/utilities.cpp b/rclcpp/src/rclcpp/utilities.cpp index 127cc7a..12fda7e 100644 --- a/rclcpp/src/rclcpp/utilities.cpp +++ b/rclcpp/src/rclcpp/utilities.cpp @@ -14,279 +14,16 @@ #include "rclcpp/utilities.hpp" -#include -#include -#include -#include -#include -#include -#include #include -#include #include +#include "./signal_handler.hpp" #include "rclcpp/contexts/default_context.hpp" -#include "rclcpp/logging.hpp" #include "rclcpp/exceptions.hpp" -#include "rclcpp/scope_exit.hpp" #include "rcl/error_handling.h" #include "rcl/rcl.h" -#include "rmw/error_handling.h" -#include "rmw/impl/cpp/demangle.hpp" -#include "rmw/rmw.h" - -#include "rcutils/logging_macros.h" - -// Determine if sigaction is available -#if __APPLE__ || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE -#define HAS_SIGACTION -#endif - -namespace rclcpp -{ - -class SignalHandler final -{ -public: - static - SignalHandler & - get_global_signal_handler() - { - static SignalHandler singleton; - return singleton; - } - - bool - install() - { - std::lock_guard lock(install_mutex_); - bool already_installed = installed_.exchange(true); - if (already_installed) { - return false; - } - try { - signal_received.exchange(false); -#ifdef HAS_SIGACTION - struct sigaction action; - memset(&action, 0, sizeof(action)); - sigemptyset(&action.sa_mask); - action.sa_sigaction = signal_handler; - action.sa_flags = SA_SIGINFO; - old_action = set_sigaction(SIGINT, action); -#else - old_signal_handler = set_signal_handler(SIGINT, signal_handler); -#endif - signal_handler_thread_ = - std::thread(&SignalHandler::deferred_signal_handler, this); - } catch (...) { - installed_.exchange(false); - throw; - } - RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "signal handler installed"); - return true; - } - - bool - uninstall() - { - std::lock_guard lock(install_mutex_); - bool installed = installed_.exchange(false); - if (!installed) { - return false; - } - try { -#ifdef HAS_SIGACTION - set_sigaction(SIGINT, old_action); -#else - set_signal_handler(SIGINT, old_signal_handler); -#endif - events_condition_variable.notify_one(); - signal_handler_thread_.join(); - } catch (...) { - installed_.exchange(true); - throw; - } - RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "signal handler uninstalled"); - return true; - } - - bool - is_installed() - { - return installed_.load(); - } - -private: - SignalHandler() = default; - - ~SignalHandler() - { - try { - uninstall(); - } catch (const std::exception & exc) { - RCLCPP_ERROR( - rclcpp::get_logger("rclcpp"), - "caught %s exception when uninstalling the sigint handler in rclcpp::~SignalHandler: %s", - rmw::impl::cpp::demangle(exc).c_str(), exc.what()); - } catch (...) { - RCLCPP_ERROR( - rclcpp::get_logger("rclcpp"), - "caught unknown exception when uninstalling the sigint handler in rclcpp::~SignalHandler"); - } - } - - // POSIX signal handler structure. -#ifdef HAS_SIGACTION - static struct sigaction old_action; -#else - typedef void (* signal_handler_t)(int); - static signal_handler_t old_signal_handler; -#endif - - static -#ifdef HAS_SIGACTION - struct sigaction - set_sigaction(int signal_value, const struct sigaction & action) -#else - signal_handler_t - set_signal_handler(int signal_value, signal_handler_t signal_handler) -#endif - { -#ifdef HAS_SIGACTION - struct sigaction old_action; - ssize_t ret = sigaction(signal_value, &action, &old_action); - if (ret == -1) -#else - signal_handler_t old_signal_handler = std::signal(signal_value, signal_handler); - // NOLINTNEXTLINE(readability/braces) - if (old_signal_handler == SIG_ERR) -#endif - { - const size_t error_length = 1024; - // NOLINTNEXTLINE(runtime/arrays) - char error_string[error_length]; -#ifndef _WIN32 -#if (defined(_GNU_SOURCE) && !defined(ANDROID)) - char * msg = strerror_r(errno, error_string, error_length); - if (msg != error_string) { - strncpy(error_string, msg, error_length); - msg[error_length - 1] = '\0'; - } -#else - int error_status = strerror_r(errno, error_string, error_length); - if (error_status != 0) { - throw std::runtime_error("Failed to get error string for errno: " + std::to_string(errno)); - } -#endif -#else - strerror_s(error_string, error_length, errno); -#endif - // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here) - throw std::runtime_error( - std::string("Failed to set SIGINT signal handler: (" + std::to_string(errno) + ")") + - error_string); - // *INDENT-ON* - } - -#ifdef HAS_SIGACTION - return old_action; -#else - return old_signal_handler; -#endif - } - - static - void -#ifdef HAS_SIGACTION - signal_handler(int signal_value, siginfo_t * siginfo, void * context) -#else - signal_handler(int signal_value) -#endif - { - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "signal_handler(signal_value=%d)", signal_value); - -#ifdef HAS_SIGACTION - if (old_action.sa_flags & SA_SIGINFO) { - if (old_action.sa_sigaction != NULL) { - old_action.sa_sigaction(signal_value, siginfo, context); - } - } else { - if ( - old_action.sa_handler != NULL && // Is set - old_action.sa_handler != SIG_DFL && // Is not default - old_action.sa_handler != SIG_IGN) // Is not ignored - { - old_action.sa_handler(signal_value); - } - } -#else - if (old_signal_handler) { - old_signal_handler(signal_value); - } -#endif - signal_received.exchange(true); - events_condition_variable.notify_one(); - } - - void - deferred_signal_handler() - { - while (true) { - if (signal_received.exchange(false)) { - for (auto context_ptr : rclcpp::get_contexts()) { - if (context_ptr->get_init_options().shutdown_on_sigint) { - context_ptr->shutdown("signal handler"); - } - } - } - if (!is_installed()) { - break; - } - std::unique_lock events_lock(events_mutex); - events_condition_variable.wait(events_lock); - } - } - - // A mutex to lock event signaling. - static std::mutex events_mutex; - // A cond var to wait on for event signaling. - static std::condition_variable events_condition_variable; - // Whether a signal has been received or not. - static std::atomic signal_received; - // A thread to defer signal handling tasks to. - std::thread signal_handler_thread_; - - // A mutex to synchronize the install() and uninstall() methods. - std::mutex install_mutex_; - // Whether this handler has been installed or not. - std::atomic installed_{false}; -}; - -} // namespace rclcpp - -// Declare static class variables for SignalHandler -std::mutex rclcpp::SignalHandler::events_mutex; -std::condition_variable rclcpp::SignalHandler::events_condition_variable; -std::atomic rclcpp::SignalHandler::signal_received; -#ifdef HAS_SIGACTION -struct sigaction rclcpp::SignalHandler::old_action; -#else -typedef void (* signal_handler_t)(int); -signal_handler_t rclcpp::SignalHandler::old_signal_handler = 0; -#endif - -/// Mutex to protect g_sigint_guard_cond_handles -static std::mutex g_sigint_guard_cond_handles_mutex; -/// Guard conditions for interrupting the rmw implementation when the global interrupt signal fired. -static std::map g_sigint_guard_cond_handles; - -/// Condition variable for timed sleep (see sleep_for). -static std::condition_variable g_interrupt_condition_variable; -/// Mutex for protecting the global condition variable. -static std::mutex g_interrupt_mutex; - void rclcpp::init(int argc, char const * const argv[], const rclcpp::InitOptions & init_options) {