-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
signal
114 lines (93 loc) · 4.52 KB
/
signal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
Copyright (C) 2018-2024 Geoffrey Daniels. https://gpdaniels.com/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef GTL_DEBUG_SIGNAL_HPP
#define GTL_DEBUG_SIGNAL_HPP
// Summary: Class to wrap signal handlers allowing the use of lambdas with scope.
#if defined(_MSC_VER)
# pragma warning(push, 0)
#endif
#include <csignal>
#include <functional>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
namespace gtl {
/// @brief The signal class implements a wrapper around signal handling allowing the use of lambdas with scope.
/// @tparam signal_number The signal number, e.g. SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, etc...
template <int signal_number>
class signal final {
private:
/// @brief The manager class is a singleton as there can only be one handler for each signal in a program.
class manager final {
private:
/// @brief Each signal manager singleton holds a lambda function to call.
std::function<void(int)> function = nullptr;
public:
/// @brief Defaulted destructor.
~manager() = default;
private:
/// @brief Defaulted constructor, made private as this is a singleton.
manager() = default;
public:
/// @brief Singleton instance accessor function.
/// @return Returns the static instance of this class.
static manager& get_instance() {
static manager instance;
return instance;
}
/// @brief Set the function to call when the signal is raised.
/// @param new_function The signal handler lambda function that raised signals are forwarded to.
/// @return Returns the previously attached signal handling lambda function.
std::function<void(int)> set_function(const std::function<void(int)> new_function) {
std::function<void(int)> old_function = this->function;
this->function = new_function;
return old_function;
}
/// @brief Clear the function to call when the signal is raised.
/// @return Returns the previously attached signal handling function.
std::function<void(int)> clear_function() {
std::function<void(int)> old_function = this->function;
this->function = nullptr;
return old_function;
}
public:
/// @brief Static signal handler function that gets the singleton instance and attempts to call the contained handler.
static void handler(int signal_id) {
if (manager::get_instance().function) {
manager::get_instance().function(signal_id);
}
}
};
private:
/// @brief The function specification of a signal handler.
using function_type = void (*)(int);
/// @brief Variable that holds any previously attached signal handler function to be restored upon destruction.
function_type old_signal_function;
/// @brief Variable that holds any previously attached single handler lambda function to be restored upon destruction.
std::function<void(int)> old_signal_lambda;
public:
/// @brief The destructor resets the signal handlers to their previous values.
~signal() {
std::signal(signal_number, this->old_signal_function);
manager::get_instance().set_function(this->old_signal_lambda);
}
/// @brief The constructor sets the signal handlers to new functions and stores their old values.
/// @param new_function The signal handler lambda function that raised signals are forwarded to.
signal(const std::function<void(int)>& new_function) {
this->old_signal_lambda = manager::get_instance().set_function(new_function);
this->old_signal_function = std::signal(signal_number, &manager::handler);
}
};
}
#endif // GTL_DEBUG_SIGNAL_HPP