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,18 +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 );
133-
134144 SignalHandler::signal_handler_type handler_argument;
135145#if defined(RCLCPP_HAS_SIGACTION)
136146 memset (&handler_argument, 0 , sizeof (handler_argument));
@@ -156,9 +166,10 @@ SignalHandler::install(SignalHandlerOptions signal_handler_options)
156166
157167 signal_handler_thread_ = std::thread (&SignalHandler::deferred_signal_handler, this );
158168 } catch (...) {
159- installed_.store (false );
160169 throw ;
161170 }
171+ installed_ = true ;
172+
162173 RCLCPP_DEBUG (get_logger (), " signal handler installed" );
163174 return true ;
164175}
@@ -167,11 +178,18 @@ bool
167178SignalHandler::uninstall ()
168179{
169180 std::lock_guard<std::mutex> lock (install_mutex_);
170- bool installed = installed_.exchange (false );
171- if (!installed) {
181+ if (!installed_) {
172182 return false ;
173183 }
184+
185+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): shutting down deferred signal handler" );
186+ notify_deferred_handler (Input::TerminateHandler);
187+ if (signal_handler_thread_.joinable ()) {
188+ signal_handler_thread_.join ();
189+ }
190+
174191 try {
192+ RCLCPP_DEBUG (get_logger (), " SignalHandler::uninstall(): restoring signal handlers" );
175193 // TODO(wjwwood): what happens if someone overrides our signal handler then calls uninstall?
176194 // I think we need to assert that we're the current signal handler, and mitigate if not.
177195 if (
@@ -187,24 +205,19 @@ SignalHandler::uninstall()
187205 set_signal_handler (SIGTERM, old_sigterm_handler_);
188206 }
189207 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 ();
196208 } catch (...) {
197- installed_.exchange (true );
198209 throw ;
199210 }
211+ installed_ = false ;
200212 RCLCPP_DEBUG (get_logger (), " signal handler uninstalled" );
201213 return true ;
202214}
203215
204216bool
205217SignalHandler::is_installed ()
206218{
207- return installed_.load ();
219+ std::lock_guard<std::mutex> lock (install_mutex_);
220+ return installed_;
208221}
209222
210223SignalHandler::~SignalHandler ()
@@ -242,143 +255,79 @@ SignalHandler::get_old_signal_handler(int signum)
242255#endif
243256}
244257
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-
254258void
255259SignalHandler::deferred_signal_handler ()
256260{
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 (
261+ bool running = true ;
262+ while (running) {
263+ std::optional<Input> next;
264+
265+ RCLCPP_DEBUG (
266+ get_logger (), " deferred_signal_handler(): waiting for SIGINT/SIGTERM or uninstall" );
267+ {
268+ std::unique_lock l (signal_mutex_);
269+ signal_conditional_.wait (l, [this ] () {
270+ return terminate_handler_ || got_sig_int || got_sig_term;
271+ });
272+
273+ if (terminate_handler_.exchange (false )) {
274+ next = Input::TerminateHandler;
275+ }
276+ if (got_sig_int.exchange (false )) {
277+ RCLCPP_INFO (SignalHandler::get_logger (), " signal_handler(SIGINT)" );
278+ next = Input::SigInt;
279+ }
280+ if (got_sig_term.exchange (false )) {
281+ RCLCPP_INFO (SignalHandler::get_logger (), " signal_handler(SIGTERM)" );
282+ next = Input::SigTerm;
283+ }
284+ }
285+ RCLCPP_DEBUG (
286+ get_logger (), " deferred_signal_handler(): woken up due to SIGINT/SIGTERM or uninstall" );
287+
288+ // Note 'next' must always be valid at this point, if not
289+ // a throw is the expected behaviour
290+ switch (next.value ()) {
291+ case Input::SigInt:
292+ [[fallthrough]];
293+ case Input::SigTerm:
294+ {
295+ RCLCPP_DEBUG (get_logger (), " deferred_signal_handler(): shutting down" );
296+ for (auto context_ptr : rclcpp::get_contexts ()) {
297+ if (context_ptr->get_init_options ().shutdown_on_signal ) {
298+ RCLCPP_DEBUG (
265299 get_logger (),
266300 " deferred_signal_handler(): "
267301 " shutting down rclcpp::Context @ %p, because it had shutdown_on_signal == true" ,
268302 static_cast <void *>(context_ptr.get ()));
269- context_ptr->shutdown (" signal handler" );
303+ context_ptr->shutdown (" signal handler" );
304+ }
305+ }
306+ break ;
270307 }
271- }
272- }
273- if (!is_installed ()) {
274- RCLCPP_DEBUG (get_logger (), " deferred_signal_handler(): signal handling uninstalled" );
275- break ;
308+ case Input::TerminateHandler:
309+ running = false ;
310+ break ;
276311 }
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" );
282312 }
283313}
284314
285315void
286- SignalHandler::setup_wait_for_signal ()
316+ SignalHandler::notify_deferred_handler (Input input) noexcept
287317{
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
318+ switch (input) {
319+ case Input::SigInt:
320+ got_sig_int.exchange (true );
341321 break ;
342- case WAIT_TIMEOUT :
343- RCLCPP_ERROR ( get_logger (), " WaitForSingleObject() timedout out in wait_for_signal() " );
322+ case Input::SigTerm :
323+ got_sig_term. exchange ( true );
344324 break ;
345- case WAIT_FAILED:
346- RCLCPP_ERROR (
347- get_logger (), " WaitForSingleObject() failed in wait_for_signal(): %s" , GetLastError ());
325+ case Input::TerminateHandler:
326+ terminate_handler_.exchange (true );
348327 break ;
349- default :
350- RCLCPP_ERROR (
351- get_logger (), " WaitForSingleObject() gave unknown return in wait_for_signal(): %s" ,
352- GetLastError ());
353328 }
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- }
363329
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
330+ signal_conditional_.notify_one ();
382331}
383332
384333rclcpp::SignalHandlerOptions
0 commit comments