Skip to content
This repository was archived by the owner on Dec 9, 2025. It is now read-only.

Commit 1fe9b8b

Browse files
committed
feature: add signal handler for termination
- a signal handler for SIGTERM and SIGINT is now registered for the modules on their initialization - this signal handler calls exit(), so that atexit handlers get run and gcov statistics can be dumped Signed-off-by: aw <aw@pionix.de>
1 parent 18a88d9 commit 1fe9b8b

File tree

1 file changed

+48
-6
lines changed

1 file changed

+48
-6
lines changed

lib/runtime.cpp

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22
// Copyright Pionix GmbH and Contributors to EVerest
33

44
#include <framework/runtime.hpp>
5+
6+
#include <algorithm>
7+
#include <atomic>
8+
#include <cstdlib>
9+
#include <fstream>
10+
11+
#include <signal.h>
12+
13+
#include <boost/program_options.hpp>
14+
515
#include <utils/error.hpp>
616
#include <utils/error/error_factory.hpp>
717
#include <utils/error/error_json.hpp>
@@ -10,16 +20,38 @@
1020
#include <utils/error/error_state_monitor.hpp>
1121
#include <utils/filesystem.hpp>
1222

13-
#include <algorithm>
14-
#include <cstdlib>
15-
#include <fstream>
16-
17-
#include <boost/program_options.hpp>
18-
1923
namespace Everest {
2024

2125
namespace po = boost::program_options;
2226

27+
namespace {
28+
29+
static std::atomic_flag going_to_terminate = ATOMIC_FLAG_INIT;
30+
31+
void terminate_handler(int signal) {
32+
if (going_to_terminate.test_and_set()) {
33+
return;
34+
}
35+
36+
// NOTE (aw): calling exit() in a signal handler is not advised due
37+
// to race condition. For now we only do that in order for getting
38+
// gcov `atexit` handlers to run (to write out coverage statistics).
39+
// This should be properly handled by an event loop in the
40+
// corresponding process.
41+
exit(EXIT_FAILURE);
42+
};
43+
44+
void setup_signal_handlers() {
45+
struct sigaction action {};
46+
action.sa_handler = &terminate_handler;
47+
// action.sa_mask should be zero, so no blocked signals within the signal handler
48+
// action.sa_flags should be fine with being zero
49+
sigaction(SIGINT, &action, nullptr);
50+
sigaction(SIGTERM, &action, nullptr);
51+
}
52+
53+
} // namespace
54+
2355
std::string parse_string_option(const po::variables_map& vm, const char* option) {
2456
if (vm.count(option) == 0) {
2557
return "";
@@ -398,6 +430,16 @@ ModuleCallbacks::ModuleCallbacks(
398430

399431
ModuleLoader::ModuleLoader(int argc, char* argv[], ModuleCallbacks callbacks, VersionInformation version_information) :
400432
runtime_settings(nullptr), callbacks(std::move(callbacks)), version_information(std::move(version_information)) {
433+
434+
// FIXME (aw): this shouldn't been done in this constructor, but
435+
// rather in a seperate `framework/module_init` function. For now
436+
// we're leaving it here as the signal handlers should be set up as
437+
// early as possible - and the `ModuleLoader` is the thing, which
438+
// gets constructed first.
439+
// NOTE (aw): it was decided not to add this call to ev-cli in order
440+
// to reduce the amount of generated code.
441+
setup_signal_handlers();
442+
401443
if (!this->parse_command_line(argc, argv)) {
402444
this->should_exit = true;
403445
return;

0 commit comments

Comments
 (0)