Skip to content

Commit 096cc95

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 096cc95

File tree

2 files changed

+85
-201
lines changed

2 files changed

+85
-201
lines changed

rclcpp/src/rclcpp/signal_handler.cpp

Lines changed: 65 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,11 @@
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
9082
void
@@ -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
119111
SignalHandler::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
167162
SignalHandler::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

204200
bool
205201
SignalHandler::is_installed()
206202
{
207-
return installed_.load();
203+
std::lock_guard<std::mutex> lock(install_mutex_);
204+
return installed_;
208205
}
209206

210207
SignalHandler::~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-
254242
void
255243
SignalHandler::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

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

384304
rclcpp::SignalHandlerOptions

0 commit comments

Comments
 (0)