15 #include "signal_handler.hpp"
27 #elif defined(__APPLE__)
28 #include <dispatch/dispatch.h>
30 #include <semaphore.h>
33 #include "rclcpp/logging.hpp"
34 #include "rclcpp/utilities.hpp"
35 #include "rcutils/strerror.h"
36 #include "rmw/impl/cpp/demangle.hpp"
41 SignalHandler::signal_handler_type
42 SignalHandler::set_signal_handler(
44 const SignalHandler::signal_handler_type & signal_handler)
46 bool signal_handler_install_failed;
47 SignalHandler::signal_handler_type old_signal_handler;
48 #if defined(RCLCPP_HAS_SIGACTION)
49 ssize_t ret = sigaction(signal_value, &signal_handler, &old_signal_handler);
50 signal_handler_install_failed = (ret == -1);
52 old_signal_handler = std::signal(signal_value, signal_handler);
53 signal_handler_install_failed = (old_signal_handler == SIG_ERR);
55 if (signal_handler_install_failed) {
56 char error_string[1024];
57 rcutils_strerror(error_string,
sizeof(error_string));
59 "Failed to set signal handler (" + std::to_string(errno) +
"): " + error_string;
60 throw std::runtime_error(msg);
62 return old_signal_handler;
67 #if defined(RCLCPP_HAS_SIGACTION)
69 SignalHandler::signal_handler(
70 int signum, siginfo_t * siginfo,
void * context)
74 auto old_signal_handler = instance.get_old_signal_handler(signum);
75 if (old_signal_handler.sa_flags & SA_SIGINFO) {
76 if (old_signal_handler.sa_sigaction != NULL) {
77 old_signal_handler.sa_sigaction(signum, siginfo, context);
81 old_signal_handler.sa_handler != NULL &&
82 old_signal_handler.sa_handler != SIG_DFL &&
83 old_signal_handler.sa_handler != SIG_IGN)
85 old_signal_handler.sa_handler(signum);
88 instance.signal_handler_common(signum);
92 SignalHandler::signal_handler(
int signum)
95 auto old_signal_handler = instance.get_old_signal_handler(signum);
97 SIG_ERR != old_signal_handler && SIG_IGN != old_signal_handler &&
98 SIG_DFL != old_signal_handler)
100 old_signal_handler(signum);
102 instance.signal_handler_common(signum);
116 return signal_handler;
122 std::lock_guard<std::mutex> lock(install_mutex_);
123 bool already_installed = installed_.exchange(
true);
124 if (already_installed) {
130 signal_handlers_options_ = signal_handler_options;
132 setup_wait_for_signal();
133 signal_received_.store(
false);
135 SignalHandler::signal_handler_type handler_argument;
136 #if defined(RCLCPP_HAS_SIGACTION)
137 memset(&handler_argument, 0,
sizeof(handler_argument));
138 sigemptyset(&handler_argument.sa_mask);
139 handler_argument.sa_sigaction = &this->signal_handler;
140 handler_argument.sa_flags = SA_SIGINFO;
142 handler_argument = &this->signal_handler;
148 old_sigint_handler_ = set_signal_handler(SIGINT, handler_argument);
155 old_sigterm_handler_ = set_signal_handler(SIGTERM, handler_argument);
158 signal_handler_thread_ = std::thread(&SignalHandler::deferred_signal_handler,
this);
160 installed_.store(
false);
163 RCLCPP_DEBUG(
get_logger(),
"signal handler installed");
170 std::lock_guard<std::mutex> lock(install_mutex_);
171 bool installed = installed_.exchange(
false);
182 set_signal_handler(SIGINT, old_sigint_handler_);
188 set_signal_handler(SIGTERM, old_sigterm_handler_);
191 RCLCPP_DEBUG(
get_logger(),
"SignalHandler::uninstall(): notifying deferred signal handler");
192 notify_signal_handler();
193 if (signal_handler_thread_.joinable()) {
194 signal_handler_thread_.join();
196 teardown_wait_for_signal();
198 installed_.exchange(
true);
201 RCLCPP_DEBUG(
get_logger(),
"signal handler uninstalled");
208 return installed_.load();
211 SignalHandler::~SignalHandler()
215 }
catch (
const std::exception & exc) {
218 "caught %s exception when uninstalling signal handlers in rclcpp::~SignalHandler: %s",
219 rmw::impl::cpp::demangle(exc).c_str(), exc.what());
223 "caught unknown exception when uninstalling signal handlers in rclcpp::~SignalHandler");
227 SignalHandler::signal_handler_type
228 SignalHandler::get_old_signal_handler(
int signum)
230 if (SIGINT == signum) {
231 return old_sigint_handler_;
232 }
else if (SIGTERM == signum) {
233 return old_sigterm_handler_;
235 #if defined(RCLCPP_HAS_SIGACTION)
236 SignalHandler::signal_handler_type ret;
237 memset(&ret, 0,
sizeof(ret));
238 sigemptyset(&ret.sa_mask);
239 ret.sa_handler = SIG_DFL;
247 SignalHandler::signal_handler_common(
int signum)
250 instance.signal_number_.store(signum);
251 instance.signal_received_.store(
true);
252 instance.notify_signal_handler();
256 SignalHandler::deferred_signal_handler()
259 if (signal_received_.exchange(
false)) {
260 int signum = signal_number_.load();
261 RCLCPP_INFO(
get_logger(),
"signal_handler(signum=%d)", signum);
262 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): shutting down");
264 if (context_ptr->get_init_options().shutdown_on_signal) {
267 "deferred_signal_handler(): "
268 "shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true",
269 static_cast<void *
>(context_ptr.get()));
271 context_ptr->shutdown(
"signal handler");
272 }
catch (
const std::exception & exc) {
277 "deferred_signal_handler(): failed to shutdown rclcpp::Context @ %p: %s",
278 static_cast<void *
>(context_ptr.get()), exc.what());
282 "deferred_signal_handler(): failed to shutdown rclcpp::Context @ %p",
283 static_cast<void *
>(context_ptr.get()));
289 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): signal handling uninstalled");
293 get_logger(),
"deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall");
296 get_logger(),
"deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall");
301 SignalHandler::setup_wait_for_signal()
304 signal_handler_sem_ = CreateSemaphore(
309 if (NULL == signal_handler_sem_) {
310 throw std::runtime_error(
"CreateSemaphore() failed in setup_wait_for_signal()");
312 #elif defined(__APPLE__)
313 signal_handler_sem_ = dispatch_semaphore_create(0);
315 if (-1 == sem_init(&signal_handler_sem_, 0, 0)) {
316 throw std::runtime_error(std::string(
"sem_init() failed: ") + strerror(errno));
319 wait_for_signal_is_setup_.store(
true);
323 SignalHandler::teardown_wait_for_signal() noexcept
325 if (!wait_for_signal_is_setup_.exchange(
false)) {
329 CloseHandle(signal_handler_sem_);
330 #elif defined(__APPLE__)
331 dispatch_release(signal_handler_sem_);
333 if (-1 == sem_destroy(&signal_handler_sem_)) {
334 RCLCPP_ERROR(
get_logger(),
"invalid semaphore in teardown_wait_for_signal()");
340 SignalHandler::wait_for_signal()
342 if (!wait_for_signal_is_setup_.load()) {
343 RCLCPP_ERROR(
get_logger(),
"called wait_for_signal() before setup_wait_for_signal()");
347 DWORD dw_wait_result = WaitForSingleObject(signal_handler_sem_, INFINITE);
348 switch (dw_wait_result) {
351 get_logger(),
"WaitForSingleObject() failed in wait_for_signal() with WAIT_ABANDONED: %s",
358 RCLCPP_ERROR(
get_logger(),
"WaitForSingleObject() timedout out in wait_for_signal()");
362 get_logger(),
"WaitForSingleObject() failed in wait_for_signal(): %s", GetLastError());
366 get_logger(),
"WaitForSingleObject() gave unknown return in wait_for_signal(): %s",
369 #elif defined(__APPLE__)
370 dispatch_semaphore_wait(signal_handler_sem_, DISPATCH_TIME_FOREVER);
374 s = sem_wait(&signal_handler_sem_);
375 }
while (-1 == s && EINTR == errno);
380 SignalHandler::notify_signal_handler() noexcept
382 if (!wait_for_signal_is_setup_.load()) {
386 if (!ReleaseSemaphore(signal_handler_sem_, 1, NULL)) {
388 get_logger(),
"ReleaseSemaphore() failed in notify_signal_handler(): %s", GetLastError());
390 #elif defined(__APPLE__)
391 dispatch_semaphore_signal(signal_handler_sem_);
393 if (-1 == sem_post(&signal_handler_sem_)) {
394 RCLCPP_ERROR(
get_logger(),
"sem_post failed in notify_signal_handler()");
402 return signal_handlers_options_;
Responsible for managing the SIGINT/SIGTERM signal handling.
static rclcpp::Logger & get_logger()
Return a global singleton logger to avoid needing to create it everywhere.
bool is_installed()
Return true if installed, false otherwise.
static SignalHandler & get_global_signal_handler()
Return the global singleton of this class.
bool install(SignalHandlerOptions signal_handler_options=SignalHandlerOptions::All)
Install the signal handler for SIGINT/SIGTERM and start the dedicated signal handling thread.
rclcpp::SignalHandlerOptions get_current_signal_handler_options()
Get the current signal handler options.
SignalHandlerOptions
Option to indicate which signal handlers rclcpp should install.
@ SigTerm
Install only a sigterm handler.
@ None
Do not install any signal handler.
@ All
Install both sigint and sigterm, this is the default behavior.
@ SigInt
Install only a sigint handler.
RCLCPP_PUBLIC std::vector< Context::SharedPtr > get_contexts()
Return a copy of the list of context shared pointers.