1616
1717#include < atomic>
1818#include < csignal>
19+ #include < future>
1920#include < mutex>
2021#include < string>
2122#include < thread>
2223
23- // includes for semaphore notification code
24- #if defined(_WIN32)
25- #include < windows.h>
26- #elif defined(__APPLE__)
27- #include < dispatch/dispatch.h>
28- #else // posix
29- #include < semaphore.h>
30- #endif
31-
3224#include " rclcpp/logging.hpp"
3325#include " rclcpp/utilities.hpp"
3426#include " rcutils/strerror.h"
@@ -84,7 +76,7 @@ SignalHandler::signal_handler(
8476 old_signal_handler.sa_handler (signum);
8577 }
8678 }
87- instance.signal_handler_common (signum );
79+ instance.notify_deferred_handler (Command::ShutdownSystem );
8880}
8981#else
9082void
@@ -98,7 +90,7 @@ SignalHandler::signal_handler(int signum)
9890 {
9991 old_signal_handler (signum);
10092 }
101- instance.signal_handler_common (signum );
93+ instance.notify_deferred_handler (Command::ShutdownSystem );
10294}
10395#endif
10496
@@ -119,17 +111,19 @@ bool
119111SignalHandler::install (SignalHandlerOptions signal_handler_options)
120112{
121113 std::lock_guard<std::mutex> lock (install_mutex_);
122- bool already_installed = installed_.exchange (true );
123- if (already_installed) {
114+ if (installed_) {
124115 return false ;
125116 }
126117 if (signal_handler_options == SignalHandlerOptions::None) {
127118 return true ;
128119 }
120+
121+ // know state in case someone uninstalls and reinstall handlers
122+ shutdown_ = false ;
123+ terminate_handler_ = false ;
124+
129125 signal_handlers_options_ = signal_handler_options;
130126 try {
131- setup_wait_for_signal ();
132- signal_received_.store (false );
133127
134128 SignalHandler::signal_handler_type handler_argument;
135129#if defined(RCLCPP_HAS_SIGACTION)
@@ -156,9 +150,10 @@ SignalHandler::install(SignalHandlerOptions signal_handler_options)
156150
157151 signal_handler_thread_ = std::thread (&SignalHandler::deferred_signal_handler, this );
158152 } catch (...) {
159- installed_.store (false );
160153 throw ;
161154 }
155+ installed_ = true ;
156+
162157 RCLCPP_DEBUG (get_logger (), " signal handler installed" );
163158 return true ;
164159}
@@ -167,11 +162,18 @@ bool
167162SignalHandler::uninstall ()
168163{
169164 std::lock_guard<std::mutex> lock (install_mutex_);
170- bool installed = installed_.exchange (false );
171- if (!installed) {
165+ if (!installed_) {
172166 return false ;
173167 }
168+
169+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): shutting down deferred signal handler" );
170+ notify_deferred_handler (Command::TerminateHandler);
171+ if (signal_handler_thread_.joinable ()) {
172+ signal_handler_thread_.join ();
173+ }
174+
174175 try {
176+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): restoring signal handlers" );
175177 // TODO(wjwwood): what happens if someone overrides our signal handler then calls uninstall?
176178 // I think we need to assert that we're the current signal handler, and mitigate if not.
177179 if (
@@ -187,24 +189,19 @@ SignalHandler::uninstall()
187189 set_signal_handler (SIGTERM, old_sigterm_handler_);
188190 }
189191 signal_handlers_options_ = SignalHandlerOptions::None;
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 ();
194- }
195- teardown_wait_for_signal ();
196192 } catch (...) {
197- installed_.exchange (true );
198193 throw ;
199194 }
195+ installed_ = false ;
200196 RCLCPP_DEBUG (get_logger (), " signal handler uninstalled" );
201197 return true ;
202198}
203199
204200bool
205201SignalHandler::is_installed ()
206202{
207- return installed_.load ();
203+ std::lock_guard<std::mutex> lock (install_mutex_);
204+ return installed_;
208205}
209206
210207SignalHandler::~SignalHandler ()
@@ -242,143 +239,66 @@ SignalHandler::get_old_signal_handler(int signum)
242239#endif
243240}
244241
245- void
246- SignalHandler::signal_handler_common (int signum)
247- {
248- auto & instance = SignalHandler::get_global_signal_handler ();
249- instance.signal_number_ .store (signum);
250- instance.signal_received_ .store (true );
251- instance.notify_signal_handler ();
252- }
253-
254242void
255243SignalHandler::deferred_signal_handler ()
256244{
257- while (true ) {
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" );
262- for (auto context_ptr : rclcpp::get_contexts ()) {
263- if (context_ptr->get_init_options ().shutdown_on_signal ) {
264- RCLCPP_DEBUG (
245+ bool running = true ;
246+ while (running) {
247+ Command next;
248+
249+ RCLCPP_DEBUG (
250+ get_logger (), " deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall" );
251+ {
252+ std::unique_lock l (signal_mutex_);
253+ signal_conditional_.wait (l, [this ] () {return terminate_handler_ || shutdown_;});
254+
255+ if (terminate_handler_.exchange (false )) {
256+ next = Command::TerminateHandler;
257+ }
258+ if (shutdown_.exchange (false )) {
259+ RCLCPP_INFO (SignalHandler::get_logger (), " signal_handler(SIGINT/SIGTERM)" );
260+ next = Command::ShutdownSystem;
261+ }
262+ }
263+ RCLCPP_DEBUG (
264+ get_logger (), " deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall" );
265+
266+ switch (next) {
267+ case Command::ShutdownSystem:
268+ {
269+ RCLCPP_DEBUG (get_logger (), " deferred_signal_handler(): shutting down" );
270+ for (auto context_ptr : rclcpp::get_contexts ()) {
271+ if (context_ptr->get_init_options ().shutdown_on_signal ) {
272+ RCLCPP_DEBUG (
265273 get_logger (),
266274 " deferred_signal_handler(): "
267275 " shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true" ,
268276 static_cast <void *>(context_ptr.get ()));
269- context_ptr->shutdown (" signal handler" );
277+ context_ptr->shutdown (" signal handler" );
278+ }
279+ }
280+ break ;
270281 }
271- }
282+ case Command::TerminateHandler:
283+ running = false ;
284+ break ;
272285 }
273- if (!is_installed ()) {
274- RCLCPP_DEBUG (get_logger (), " deferred_signal_handler(): signal handling uninstalled" );
275- break ;
276- }
277- RCLCPP_DEBUG (
278- get_logger (), " deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall" );
279- wait_for_signal ();
280- RCLCPP_DEBUG (
281- get_logger (), " deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall" );
282286 }
283287}
284288
285289void
286- SignalHandler::setup_wait_for_signal ()
290+ SignalHandler::notify_deferred_handler (Command wanted_response) noexcept
287291{
288- #if defined(_WIN32)
289- signal_handler_sem_ = CreateSemaphore (
290- NULL , // default security attributes
291- 0 , // initial semaphore count
292- 1 , // maximum semaphore count
293- NULL ); // unnamed semaphore
294- if (NULL == signal_handler_sem_) {
295- throw std::runtime_error (" CreateSemaphore() failed in setup_wait_for_signal()" );
296- }
297- #elif defined(__APPLE__)
298- signal_handler_sem_ = dispatch_semaphore_create (0 );
299- #else // posix
300- if (-1 == sem_init (&signal_handler_sem_, 0 , 0 )) {
301- throw std::runtime_error (std::string (" sem_init() failed: " ) + strerror (errno));
302- }
303- #endif
304- wait_for_signal_is_setup_.store (true );
305- }
306-
307- void
308- SignalHandler::teardown_wait_for_signal () noexcept
309- {
310- if (!wait_for_signal_is_setup_.exchange (false )) {
311- return ;
312- }
313- #if defined(_WIN32)
314- CloseHandle (signal_handler_sem_);
315- #elif defined(__APPLE__)
316- dispatch_release (signal_handler_sem_);
317- #else // posix
318- if (-1 == sem_destroy (&signal_handler_sem_)) {
319- RCLCPP_ERROR (get_logger (), " invalid semaphore in teardown_wait_for_signal()" );
320- }
321- #endif
322- }
323-
324- void
325- SignalHandler::wait_for_signal ()
326- {
327- if (!wait_for_signal_is_setup_.load ()) {
328- RCLCPP_ERROR (get_logger (), " called wait_for_signal() before setup_wait_for_signal()" );
329- return ;
330- }
331- #if defined(_WIN32)
332- DWORD dw_wait_result = WaitForSingleObject (signal_handler_sem_, INFINITE);
333- switch (dw_wait_result) {
334- case WAIT_ABANDONED:
335- RCLCPP_ERROR (
336- get_logger (), " WaitForSingleObject() failed in wait_for_signal() with WAIT_ABANDONED: %s" ,
337- GetLastError ());
338- break ;
339- case WAIT_OBJECT_0:
340- // successful
292+ switch (wanted_response) {
293+ case Command::ShutdownSystem:
294+ shutdown_.exchange (true );
341295 break ;
342- case WAIT_TIMEOUT :
343- RCLCPP_ERROR ( get_logger (), " WaitForSingleObject() timedout out in wait_for_signal() " );
296+ case Command::TerminateHandler :
297+ terminate_handler_. exchange ( true );
344298 break ;
345- case WAIT_FAILED:
346- RCLCPP_ERROR (
347- get_logger (), " WaitForSingleObject() failed in wait_for_signal(): %s" , GetLastError ());
348- break ;
349- default :
350- RCLCPP_ERROR (
351- get_logger (), " WaitForSingleObject() gave unknown return in wait_for_signal(): %s" ,
352- GetLastError ());
353299 }
354- #elif defined(__APPLE__)
355- dispatch_semaphore_wait (signal_handler_sem_, DISPATCH_TIME_FOREVER);
356- #else // posix
357- int s;
358- do {
359- s = sem_wait (&signal_handler_sem_);
360- } while (-1 == s && EINTR == errno);
361- #endif
362- }
363300
364- void
365- SignalHandler::notify_signal_handler () noexcept
366- {
367- if (!wait_for_signal_is_setup_.load ()) {
368- return ;
369- }
370- #if defined(_WIN32)
371- if (!ReleaseSemaphore (signal_handler_sem_, 1 , NULL )) {
372- RCLCPP_ERROR (
373- get_logger (), " ReleaseSemaphore() failed in notify_signal_handler(): %s" , GetLastError ());
374- }
375- #elif defined(__APPLE__)
376- dispatch_semaphore_signal (signal_handler_sem_);
377- #else // posix
378- if (-1 == sem_post (&signal_handler_sem_)) {
379- RCLCPP_ERROR (get_logger (), " sem_post failed in notify_signal_handler()" );
380- }
381- #endif
301+ signal_conditional_.notify_one ();
382302}
383303
384304rclcpp::SignalHandlerOptions
0 commit comments