Skip to content

Commit 399f671

Browse files
Janosch MachowinskiJanosch Machowinski
authored andcommitted
refactor: Use std::conditional_variable in signal handler code
Code cleanup to use std::conditional_variable in the signal handler code instead of a custom home brew version. Signed-off-by: Janosch Machowinski <[email protected]>
1 parent 95cb964 commit 399f671

File tree

2 files changed

+116
-198
lines changed

2 files changed

+116
-198
lines changed

rclcpp/src/rclcpp/signal_handler.cpp

Lines changed: 92 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,12 @@
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+
105113
rclcpp::Logger &
106114
SignalHandler::get_logger()
107115
{
@@ -119,17 +127,20 @@ bool
119127
SignalHandler::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
167179
SignalHandler::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

204217
bool
205218
SignalHandler::is_installed()
206219
{
207-
return installed_.load();
220+
std::lock_guard<std::mutex> lock(install_mutex_);
221+
return installed_;
208222
}
209223

210224
SignalHandler::~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-
254259
void
255260
SignalHandler::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

324316
void
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

384334
rclcpp::SignalHandlerOptions

0 commit comments

Comments
 (0)