15 #include "signal_handler.hpp"
26 #elif defined(__APPLE__)
27 #include <dispatch/dispatch.h>
29 #include <semaphore.h>
32 #include "rclcpp/logging.hpp"
33 #include "rclcpp/utilities.hpp"
34 #include "rcutils/strerror.h"
35 #include "rmw/impl/cpp/demangle.hpp"
40 SignalHandler::signal_handler_type
41 SignalHandler::set_signal_handler(
43 const SignalHandler::signal_handler_type & signal_handler)
45 bool signal_handler_install_failed;
46 SignalHandler::signal_handler_type old_signal_handler;
47 #if defined(RCLCPP_HAS_SIGACTION)
48 ssize_t ret = sigaction(signal_value, &signal_handler, &old_signal_handler);
49 signal_handler_install_failed = (ret == -1);
51 old_signal_handler = std::signal(signal_value, signal_handler);
52 signal_handler_install_failed = (old_signal_handler == SIG_ERR);
54 if (signal_handler_install_failed) {
55 char error_string[1024];
56 rcutils_strerror(error_string,
sizeof(error_string));
58 "Failed to set signal handler (" + std::to_string(errno) +
"): " + error_string;
59 throw std::runtime_error(msg);
61 return old_signal_handler;
66 #if defined(RCLCPP_HAS_SIGACTION)
68 SignalHandler::signal_handler(
69 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();
92 SignalHandler::signal_handler(
int signum)
96 auto old_signal_handler = instance.get_old_signal_handler(signum);
98 SIG_ERR != old_signal_handler && SIG_IGN != old_signal_handler &&
99 SIG_DFL != old_signal_handler)
101 old_signal_handler(signum);
103 instance.signal_handler_common();
117 return signal_handler;
123 std::lock_guard<std::mutex> lock(install_mutex_);
124 bool already_installed = installed_.exchange(
true);
125 if (already_installed) {
131 signal_handlers_options_ = signal_handler_options;
133 setup_wait_for_signal();
134 signal_received_.store(
false);
136 SignalHandler::signal_handler_type handler_argument;
137 #if defined(RCLCPP_HAS_SIGACTION)
138 memset(&handler_argument, 0,
sizeof(handler_argument));
139 sigemptyset(&handler_argument.sa_mask);
140 handler_argument.sa_sigaction = &this->signal_handler;
141 handler_argument.sa_flags = SA_SIGINFO;
143 handler_argument = &this->signal_handler;
149 old_sigint_handler_ = set_signal_handler(SIGINT, handler_argument);
156 old_sigterm_handler_ = set_signal_handler(SIGTERM, handler_argument);
159 signal_handler_thread_ = std::thread(&SignalHandler::deferred_signal_handler,
this);
161 installed_.store(
false);
164 RCLCPP_DEBUG(
get_logger(),
"signal handler installed");
171 std::lock_guard<std::mutex> lock(install_mutex_);
172 bool installed = installed_.exchange(
false);
183 set_signal_handler(SIGINT, old_sigint_handler_);
189 set_signal_handler(SIGTERM, old_sigterm_handler_);
192 RCLCPP_DEBUG(
get_logger(),
"SignalHandler::uninstall(): notifying deferred signal handler");
193 notify_signal_handler();
194 if (signal_handler_thread_.joinable()) {
195 signal_handler_thread_.join();
197 teardown_wait_for_signal();
199 installed_.exchange(
true);
202 RCLCPP_DEBUG(
get_logger(),
"signal handler uninstalled");
209 return installed_.load();
212 SignalHandler::~SignalHandler()
216 }
catch (
const std::exception & exc) {
219 "caught %s exception when uninstalling signal handlers in rclcpp::~SignalHandler: %s",
220 rmw::impl::cpp::demangle(exc).c_str(), exc.what());
224 "caught unknown exception when uninstalling signal handlers in rclcpp::~SignalHandler");
228 SignalHandler::signal_handler_type
229 SignalHandler::get_old_signal_handler(
int signum)
231 if (SIGINT == signum) {
232 return old_sigint_handler_;
233 }
else if (SIGTERM == signum) {
234 return old_sigterm_handler_;
236 #if defined(RCLCPP_HAS_SIGACTION)
237 SignalHandler::signal_handler_type ret;
238 memset(&ret, 0,
sizeof(ret));
239 sigemptyset(&ret.sa_mask);
240 ret.sa_handler = SIG_DFL;
248 SignalHandler::signal_handler_common()
251 instance.signal_received_.store(
true);
254 "signal_handler(): notifying deferred signal handler");
255 instance.notify_signal_handler();
259 SignalHandler::deferred_signal_handler()
262 if (signal_received_.exchange(
false)) {
263 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): shutting down");
265 if (context_ptr->get_init_options().shutdown_on_signal) {
268 "deferred_signal_handler(): "
269 "shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true",
270 static_cast<void *
>(context_ptr.get()));
271 context_ptr->shutdown(
"signal handler");
276 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): signal handling uninstalled");
280 get_logger(),
"deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall");
283 get_logger(),
"deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall");
288 SignalHandler::setup_wait_for_signal()
291 signal_handler_sem_ = CreateSemaphore(
296 if (NULL == signal_handler_sem_) {
297 throw std::runtime_error(
"CreateSemaphore() failed in setup_wait_for_signal()");
299 #elif defined(__APPLE__)
300 signal_handler_sem_ = dispatch_semaphore_create(0);
302 if (-1 == sem_init(&signal_handler_sem_, 0, 0)) {
303 throw std::runtime_error(std::string(
"sem_init() failed: ") + strerror(errno));
306 wait_for_signal_is_setup_.store(
true);
310 SignalHandler::teardown_wait_for_signal() noexcept
312 if (!wait_for_signal_is_setup_.exchange(
false)) {
316 CloseHandle(signal_handler_sem_);
317 #elif defined(__APPLE__)
318 dispatch_release(signal_handler_sem_);
320 if (-1 == sem_destroy(&signal_handler_sem_)) {
321 RCLCPP_ERROR(
get_logger(),
"invalid semaphore in teardown_wait_for_signal()");
327 SignalHandler::wait_for_signal()
329 if (!wait_for_signal_is_setup_.load()) {
330 RCLCPP_ERROR(
get_logger(),
"called wait_for_signal() before setup_wait_for_signal()");
334 DWORD dw_wait_result = WaitForSingleObject(signal_handler_sem_, INFINITE);
335 switch (dw_wait_result) {
338 get_logger(),
"WaitForSingleObject() failed in wait_for_signal() with WAIT_ABANDONED: %s",
345 RCLCPP_ERROR(
get_logger(),
"WaitForSingleObject() timedout out in wait_for_signal()");
349 get_logger(),
"WaitForSingleObject() failed in wait_for_signal(): %s", GetLastError());
353 get_logger(),
"WaitForSingleObject() gave unknown return in wait_for_signal(): %s",
356 #elif defined(__APPLE__)
357 dispatch_semaphore_wait(signal_handler_sem_, DISPATCH_TIME_FOREVER);
361 s = sem_wait(&signal_handler_sem_);
362 }
while (-1 == s && EINTR == errno);
367 SignalHandler::notify_signal_handler() noexcept
369 if (!wait_for_signal_is_setup_.load()) {
373 if (!ReleaseSemaphore(signal_handler_sem_, 1, NULL)) {
375 get_logger(),
"ReleaseSemaphore() failed in notify_signal_handler(): %s", GetLastError());
377 #elif defined(__APPLE__)
378 dispatch_semaphore_signal(signal_handler_sem_);
380 if (-1 == sem_post(&signal_handler_sem_)) {
381 RCLCPP_ERROR(
get_logger(),
"sem_post failed in notify_signal_handler()");
389 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.