|
2 | 2 | // Copyright Pionix GmbH and Contributors to EVerest |
3 | 3 |
|
4 | 4 | #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 | + |
5 | 15 | #include <utils/error.hpp> |
6 | 16 | #include <utils/error/error_factory.hpp> |
7 | 17 | #include <utils/error/error_json.hpp> |
|
10 | 20 | #include <utils/error/error_state_monitor.hpp> |
11 | 21 | #include <utils/filesystem.hpp> |
12 | 22 |
|
13 | | -#include <algorithm> |
14 | | -#include <cstdlib> |
15 | | -#include <fstream> |
16 | | - |
17 | | -#include <boost/program_options.hpp> |
18 | | - |
19 | 23 | namespace Everest { |
20 | 24 |
|
21 | 25 | namespace po = boost::program_options; |
22 | 26 |
|
| 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 | + |
23 | 55 | std::string parse_string_option(const po::variables_map& vm, const char* option) { |
24 | 56 | if (vm.count(option) == 0) { |
25 | 57 | return ""; |
@@ -398,6 +430,16 @@ ModuleCallbacks::ModuleCallbacks( |
398 | 430 |
|
399 | 431 | ModuleLoader::ModuleLoader(int argc, char* argv[], ModuleCallbacks callbacks, VersionInformation version_information) : |
400 | 432 | 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 | + |
401 | 443 | if (!this->parse_command_line(argc, argv)) { |
402 | 444 | this->should_exit = true; |
403 | 445 | return; |
|
0 commit comments