1616
1717#include < atomic>
1818#include < csignal>
19+ #include < future>
20+ #include < optional>
1921#include < mutex>
2022#include < string>
2123#include < thread>
2224
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-
3225#include " rclcpp/logging.hpp"
3326#include " rclcpp/utilities.hpp"
3427#include " rcutils/strerror.h"
@@ -102,6 +95,21 @@ SignalHandler::signal_handler(int signum)
10295}
10396#endif
10497
98+ void rclcpp::SignalHandler::signal_handler_common (int signum) noexcept
99+ {
100+ switch (signum) {
101+ case SIGTERM:
102+ notify_deferred_handler (Input::SigTerm);
103+ break ;
104+ case SIGINT:
105+ notify_deferred_handler (Input::SigInt);
106+ break ;
107+ default :
108+ break ;
109+ }
110+ }
111+
112+
105113rclcpp::Logger &
106114SignalHandler::get_logger ()
107115{
@@ -119,17 +127,20 @@ bool
119127SignalHandler::install (SignalHandlerOptions signal_handler_options)
120128{
121129 std::lock_guard<std::mutex> lock (install_mutex_);
122- bool already_installed = installed_.exchange (true );
123- if (already_installed) {
130+ if (installed_) {
124131 return false ;
125132 }
126133 if (signal_handler_options == SignalHandlerOptions::None) {
127134 return true ;
128135 }
136+
137+ // Reset state in case someone uninstalls and reinstall handlers
138+ got_sig_int = false ;
139+ got_sig_term = false ;
140+ terminate_handler_ = false ;
141+
129142 signal_handlers_options_ = signal_handler_options;
130143 try {
131- setup_wait_for_signal ();
132- signal_received_.store (false );
133144
134145 SignalHandler::signal_handler_type handler_argument;
135146#if defined(RCLCPP_HAS_SIGACTION)
@@ -156,9 +167,10 @@ SignalHandler::install(SignalHandlerOptions signal_handler_options)
156167
157168 signal_handler_thread_ = std::thread (&SignalHandler::deferred_signal_handler, this );
158169 } catch (...) {
159- installed_.store (false );
160170 throw ;
161171 }
172+ installed_ = true ;
173+
162174 RCLCPP_DEBUG (get_logger (), " signal handler installed" );
163175 return true ;
164176}
@@ -167,11 +179,18 @@ bool
167179SignalHandler::uninstall ()
168180{
169181 std::lock_guard<std::mutex> lock (install_mutex_);
170- bool installed = installed_.exchange (false );
171- if (!installed) {
182+ if (!installed_) {
172183 return false ;
173184 }
185+
186+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): shutting down deferred signal handler" );
187+ notify_deferred_handler (Input::TerminateHandler);
188+ if (signal_handler_thread_.joinable ()) {
189+ signal_handler_thread_.join ();
190+ }
191+
174192 try {
193+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): restoring signal handlers" );
175194 // TODO(wjwwood): what happens if someone overrides our signal handler then calls uninstall?
176195 // I think we need to assert that we're the current signal handler, and mitigate if not.
177196 if (
@@ -187,24 +206,19 @@ SignalHandler::uninstall()
187206 set_signal_handler (SIGTERM, old_sigterm_handler_);
188207 }
189208 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 ();
196209 } catch (...) {
197- installed_.exchange (true );
198210 throw ;
199211 }
212+ installed_ = false ;
200213 RCLCPP_DEBUG (get_logger (), " signal handler uninstalled" );
201214 return true ;
202215}
203216
204217bool
205218SignalHandler::is_installed ()
206219{
207- return installed_.load ();
220+ std::lock_guard<std::mutex> lock (install_mutex_);
221+ return installed_;
208222}
209223
210224SignalHandler::~SignalHandler ()
@@ -242,143 +256,79 @@ SignalHandler::get_old_signal_handler(int signum)
242256#endif
243257}
244258
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-
254259void
255260SignalHandler::deferred_signal_handler ()
256261{
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 (
262+ bool running = true ;
263+ while (running) {
264+ std::optional<Input> next;
265+
266+ RCLCPP_DEBUG (
267+ get_logger (), " deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall" );
268+ {
269+ std::unique_lock l (signal_mutex_);
270+ signal_conditional_.wait (l, [this ] () {
271+ return terminate_handler_ || got_sig_int || got_sig_term;
272+ });
273+
274+ if (terminate_handler_.exchange (false )) {
275+ next = Input::TerminateHandler;
276+ }
277+ if (got_sig_int.exchange (false )) {
278+ RCLCPP_INFO (SignalHandler::get_logger (), " signal_handler(SIGINT)" );
279+ next = Input::SigInt;
280+ }
281+ if (got_sig_term.exchange (false )) {
282+ RCLCPP_INFO (SignalHandler::get_logger (), " signal_handler(SIGTERM)" );
283+ next = Input::SigTerm;
284+ }
285+ }
286+ RCLCPP_DEBUG (
287+ get_logger (), " deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall" );
288+
289+ // Note 'next' must always be valid at this point, if not
290+ // a throw is the expected behaviour
291+ switch (next.value ()) {
292+ case Input::SigInt:
293+ [[fallthrough]];
294+ case Input::SigTerm:
295+ {
296+ RCLCPP_DEBUG (get_logger (), " deferred_signal_handler(): shutting down" );
297+ for (auto context_ptr : rclcpp::get_contexts ()) {
298+ if (context_ptr->get_init_options ().shutdown_on_signal ) {
299+ RCLCPP_DEBUG (
265300 get_logger (),
266301 " deferred_signal_handler(): "
267302 " shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true" ,
268303 static_cast <void *>(context_ptr.get ()));
269- context_ptr->shutdown (" signal handler" );
304+ context_ptr->shutdown (" signal handler" );
305+ }
306+ }
307+ break ;
270308 }
271- }
309+ case Input::TerminateHandler:
310+ running = false ;
311+ break ;
272312 }
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" );
282- }
283- }
284-
285- void
286- SignalHandler::setup_wait_for_signal ()
287- {
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 ;
312313 }
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
322314}
323315
324316void
325- SignalHandler::wait_for_signal ()
317+ SignalHandler::notify_deferred_handler (Input input) noexcept
326318{
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
319+ switch (input) {
320+ case Input::SigInt:
321+ got_sig_int.exchange (true );
341322 break ;
342- case WAIT_TIMEOUT :
343- RCLCPP_ERROR ( get_logger (), " WaitForSingleObject() timedout out in wait_for_signal() " );
323+ case Input::SigTerm :
324+ got_sig_term. exchange ( true );
344325 break ;
345- case WAIT_FAILED:
346- RCLCPP_ERROR (
347- get_logger (), " WaitForSingleObject() failed in wait_for_signal(): %s" , GetLastError ());
326+ case Input::TerminateHandler:
327+ terminate_handler_.exchange (true );
348328 break ;
349- default :
350- RCLCPP_ERROR (
351- get_logger (), " WaitForSingleObject() gave unknown return in wait_for_signal(): %s" ,
352- GetLastError ());
353329 }
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- }
363330
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
331+ signal_conditional_.notify_one ();
382332}
383333
384334rclcpp::SignalHandlerOptions
0 commit comments