forked from cryfs/cryfs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSignalCatcher.cpp
More file actions
133 lines (104 loc) · 4.23 KB
/
SignalCatcher.cpp
File metadata and controls
133 lines (104 loc) · 4.23 KB
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "SignalCatcher.h"
#include "SignalHandler.h"
#include <algorithm>
#include <stdexcept>
#include <vector>
#include <cpp-utils/assert/assert.h>
#include <cpp-utils/thread/LeftRight.h>
using std::make_unique;
using std::vector;
using std::pair;
namespace cpputils {
namespace {
void got_signal(int signal);
class SignalCatcherRegistry final {
public:
void add(int signal, details::SignalCatcherImpl* signal_occurred_flag) {
_catchers.write([&] (auto& catchers) {
catchers.emplace_back(signal, signal_occurred_flag);
});
}
void remove(details::SignalCatcherImpl* catcher) {
_catchers.write([&] (auto& catchers) {
auto found = std::find_if(catchers.rbegin(), catchers.rend(), [catcher] (const auto& entry) {return entry.second == catcher;});
ASSERT(found != catchers.rend(), "Signal handler not found");
catchers.erase(--found.base()); // decrement because it's a reverse iterator
});
}
~SignalCatcherRegistry() {
ASSERT(0 == _catchers.read([] (auto& catchers) {return catchers.size();}), "Leftover signal catchers that weren't destroyed");
}
details::SignalCatcherImpl* find(int signal) {
// this is called in a signal handler and must be mutex-free.
return _catchers.read([&](auto& catchers) {
auto found = std::find_if(catchers.rbegin(), catchers.rend(), [signal](const auto& entry) {return entry.first == signal; });
ASSERT(found != catchers.rend(), "Signal handler not found");
return found->second;
});
}
static SignalCatcherRegistry& singleton() {
static SignalCatcherRegistry _singleton;
return _singleton;
}
private:
SignalCatcherRegistry() = default;
// using LeftRight datastructure because we need mutex-free reads. Signal handlers can't use mutexes.
LeftRight<vector<pair<int, details::SignalCatcherImpl*>>> _catchers;
DISALLOW_COPY_AND_ASSIGN(SignalCatcherRegistry);
};
class SignalCatcherRegisterer final {
public:
SignalCatcherRegisterer(int signal, details::SignalCatcherImpl* catcher)
: _catcher(catcher) {
SignalCatcherRegistry::singleton().add(signal, _catcher);
}
~SignalCatcherRegisterer() {
SignalCatcherRegistry::singleton().remove(_catcher);
}
private:
details::SignalCatcherImpl* _catcher;
DISALLOW_COPY_AND_ASSIGN(SignalCatcherRegisterer);
};
}
namespace details {
class SignalCatcherImpl final {
public:
SignalCatcherImpl(int signal, std::atomic<bool>* signal_occurred_flag)
: _signal_occurred_flag(signal_occurred_flag)
, _registerer(signal, this)
, _handler(signal) {
// note: the order of the members ensures that:
// - when registering the signal handler, the SignalCatcher impl already has a valid _signal_occurred_flag set.
// - when registering the signal handler fails, the _registerer will be destroyed again, unregistering this SignalCatcherImpl,
// i.e. there is no leak.
// Allow only the set of signals that is supported on all platforms, see for Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal?view=vs-2017
ASSERT(signal == SIGABRT || signal == SIGFPE || signal == SIGILL || signal == SIGINT || signal == SIGSEGV || signal == SIGTERM, "Unknown signal");
}
void setSignalOccurred() {
*_signal_occurred_flag = true;
}
private:
std::atomic<bool>* _signal_occurred_flag;
SignalCatcherRegisterer _registerer;
SignalHandlerRAII<&got_signal> _handler;
DISALLOW_COPY_AND_ASSIGN(SignalCatcherImpl);
};
}
namespace {
void got_signal(int signal) {
SignalCatcherRegistry::singleton().find(signal)->setSignalOccurred();
}
}
SignalCatcher::SignalCatcher(std::initializer_list<int> signals)
: _signal_occurred(false)
, _impls() {
// note: the order of the members ensures that:
// - when the signal handler is set, the _signal_occurred flag is already initialized.
// - the _signal_occurred flag will not be destructed as long as the signal handler might be called (i.e. as long as _impls lives)
_impls.reserve(signals.size());
for (int signal : signals) {
_impls.emplace_back(make_unique<details::SignalCatcherImpl>(signal, &_signal_occurred));
}
}
SignalCatcher::~SignalCatcher() {}
}