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)
73 auto old_signal_handler = instance.get_old_signal_handler(signum);
74 if (old_signal_handler.sa_flags & SA_SIGINFO) {
75 if (old_signal_handler.sa_sigaction != NULL) {
76 old_signal_handler.sa_sigaction(signum, siginfo, context);
80 old_signal_handler.sa_handler != NULL &&
81 old_signal_handler.sa_handler != SIG_DFL &&
82 old_signal_handler.sa_handler != SIG_IGN)
84 old_signal_handler.sa_handler(signum);
87 instance.signal_handler_common(signum);
91 SignalHandler::signal_handler(
int signum)
94 auto old_signal_handler = instance.get_old_signal_handler(signum);
96 SIG_ERR != old_signal_handler && SIG_IGN != old_signal_handler &&
97 SIG_DFL != old_signal_handler)
99 old_signal_handler(signum);
101 instance.signal_handler_common(signum);
115 return signal_handler;
121 std::lock_guard<std::mutex> lock(install_mutex_);
122 bool already_installed = installed_.exchange(
true);
123 if (already_installed) {
129 signal_handlers_options_ = signal_handler_options;
131 setup_wait_for_signal();
132 signal_received_.store(
false);
134 SignalHandler::signal_handler_type handler_argument;
135 #if defined(RCLCPP_HAS_SIGACTION)
136 memset(&handler_argument, 0,
sizeof(handler_argument));
137 sigemptyset(&handler_argument.sa_mask);
138 handler_argument.sa_sigaction = &this->signal_handler;
139 handler_argument.sa_flags = SA_SIGINFO;
141 handler_argument = &this->signal_handler;
147 old_sigint_handler_ = set_signal_handler(SIGINT, handler_argument);
154 old_sigterm_handler_ = set_signal_handler(SIGTERM, handler_argument);
157 signal_handler_thread_ = std::thread(&SignalHandler::deferred_signal_handler,
this);
159 installed_.store(
false);
162 RCLCPP_DEBUG(
get_logger(),
"signal handler installed");
169 std::lock_guard<std::mutex> lock(install_mutex_);
170 bool installed = installed_.exchange(
false);
181 set_signal_handler(SIGINT, old_sigint_handler_);
187 set_signal_handler(SIGTERM, old_sigterm_handler_);
190 RCLCPP_DEBUG(
get_logger(),
"SignalHandler::uninstall(): notifying deferred signal handler");
191 notify_signal_handler();
192 if (signal_handler_thread_.joinable()) {
193 signal_handler_thread_.join();
195 teardown_wait_for_signal();
197 installed_.exchange(
true);
200 RCLCPP_DEBUG(
get_logger(),
"signal handler uninstalled");
207 return installed_.load();
210 SignalHandler::~SignalHandler()
214 }
catch (
const std::exception & exc) {
217 "caught %s exception when uninstalling signal handlers in rclcpp::~SignalHandler: %s",
218 rmw::impl::cpp::demangle(exc).c_str(), exc.what());
222 "caught unknown exception when uninstalling signal handlers in rclcpp::~SignalHandler");
226 SignalHandler::signal_handler_type
227 SignalHandler::get_old_signal_handler(
int signum)
229 if (SIGINT == signum) {
230 return old_sigint_handler_;
231 }
else if (SIGTERM == signum) {
232 return old_sigterm_handler_;
234 #if defined(RCLCPP_HAS_SIGACTION)
235 SignalHandler::signal_handler_type ret;
236 memset(&ret, 0,
sizeof(ret));
237 sigemptyset(&ret.sa_mask);
238 ret.sa_handler = SIG_DFL;
246 SignalHandler::signal_handler_common(
int signum)
249 instance.signal_number_.store(signum);
250 instance.signal_received_.store(
true);
251 instance.notify_signal_handler();
255 SignalHandler::deferred_signal_handler()
258 if (signal_received_.exchange(
false)) {
259 int signum = signal_number_.load();
260 RCLCPP_INFO(
get_logger(),
"signal_handler(signum=%d)", signum);
261 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): shutting down");
263 if (context_ptr->get_init_options().shutdown_on_signal) {
266 "deferred_signal_handler(): "
267 "shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true",
268 static_cast<void *
>(context_ptr.get()));
269 context_ptr->shutdown(
"signal handler");
274 RCLCPP_DEBUG(
get_logger(),
"deferred_signal_handler(): signal handling uninstalled");
278 get_logger(),
"deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall");
281 get_logger(),
"deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall");
286 SignalHandler::setup_wait_for_signal()
289 signal_handler_sem_ = CreateSemaphore(
294 if (NULL == signal_handler_sem_) {
295 throw std::runtime_error(
"CreateSemaphore() failed in setup_wait_for_signal()");
297 #elif defined(__APPLE__)
298 signal_handler_sem_ = dispatch_semaphore_create(0);
300 if (-1 == sem_init(&signal_handler_sem_, 0, 0)) {
301 throw std::runtime_error(std::string(
"sem_init() failed: ") + strerror(errno));
304 wait_for_signal_is_setup_.store(
true);
308 SignalHandler::teardown_wait_for_signal() noexcept
310 if (!wait_for_signal_is_setup_.exchange(
false)) {
314 CloseHandle(signal_handler_sem_);
315 #elif defined(__APPLE__)
316 dispatch_release(signal_handler_sem_);
318 if (-1 == sem_destroy(&signal_handler_sem_)) {
319 RCLCPP_ERROR(
get_logger(),
"invalid semaphore in teardown_wait_for_signal()");
325 SignalHandler::wait_for_signal()
327 if (!wait_for_signal_is_setup_.load()) {
328 RCLCPP_ERROR(
get_logger(),
"called wait_for_signal() before setup_wait_for_signal()");
332 DWORD dw_wait_result = WaitForSingleObject(signal_handler_sem_, INFINITE);
333 switch (dw_wait_result) {
336 get_logger(),
"WaitForSingleObject() failed in wait_for_signal() with WAIT_ABANDONED: %s",
343 RCLCPP_ERROR(
get_logger(),
"WaitForSingleObject() timedout out in wait_for_signal()");
347 get_logger(),
"WaitForSingleObject() failed in wait_for_signal(): %s", GetLastError());
351 get_logger(),
"WaitForSingleObject() gave unknown return in wait_for_signal(): %s",
354 #elif defined(__APPLE__)
355 dispatch_semaphore_wait(signal_handler_sem_, DISPATCH_TIME_FOREVER);
359 s = sem_wait(&signal_handler_sem_);
360 }
while (-1 == s && EINTR == errno);
365 SignalHandler::notify_signal_handler() noexcept
367 if (!wait_for_signal_is_setup_.load()) {
371 if (!ReleaseSemaphore(signal_handler_sem_, 1, NULL)) {
373 get_logger(),
"ReleaseSemaphore() failed in notify_signal_handler(): %s", GetLastError());
375 #elif defined(__APPLE__)
376 dispatch_semaphore_signal(signal_handler_sem_);
378 if (-1 == sem_post(&signal_handler_sem_)) {
379 RCLCPP_ERROR(
get_logger(),
"sem_post failed in notify_signal_handler()");
387 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.