Kea: signal_set.cc Source File

| Kea 1.5.0

signal_set.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <util/signal_set.h>
10
11 #include <cerrno>
12 #include <list>
13
14 using namespace isc;
15 using namespace isc::util;
16
17 namespace {
18
28 SigIntSetPtr getRegisteredSignals() {
29 static SigIntSetPtr registered_signals(new SigIntSet());
30 return (registered_signals);
31 }
32
42 SigIntListPtr getSignalStates() {
43 static SigIntListPtr signal_states(new SigIntList());
44 return (signal_states);
45 }
46
59 void internalHandler(int sig) {
60 if (SignalSet::invokeOnReceiptHandler(sig)) {
61 // Signal has been handled by the on-receipt handler.
62 return;
63 }
64
65 // Signal is using post-receipt handling, see if we've
66 // already received it.
67 SigIntListPtr states = getSignalStates();
68 for (std::list<int>::const_iterator it = states->begin();
69 it != states->end(); ++it) {
70 if (sig == *it) {
71 return;
72 }
73 }
74
75 // First occurrence, so save it.
76 states->push_back(sig);
77 }
78
80 BoolSignalHandler onreceipt_handler_ = BoolSignalHandler();
81
82 }; // end anon namespace
83
84 namespace isc {
85 namespace util {
86
87 bool
88 SignalSet::invokeOnReceiptHandler(int sig) {
89 if (!onreceipt_handler_) {
90 return (false);
91 }
92
93 // First we set the signal to SIG_IGN. This causes any repeat occurrences
94 // to be discarded, not deferred as they would be if blocked. Note that
95 // we save the current sig action so we can restore it later.
96 struct sigaction sa;
97 struct sigaction prev_sa;
98 memset(&sa, 0, sizeof(sa));
99 sa.sa_handler = SIG_IGN;
100 if (sigaction(sig, &sa, &prev_sa) < 0) {
101 // Highly unlikely we can get here.
102 const char* errmsg = strerror(errno);
103 isc_throw(SignalSetError, "failed to set SIG_IGN for signal "
104 << sig << ": " << errmsg);
105 }
106
107 // Call the registered handler.
108 bool signal_processed = false;
109 try {
110 signal_processed = onreceipt_handler_(sig);
111 } catch (const std::exception& ex) {
112 // Restore the handler. We might fail to restore it, but we likely
113 // have bigger issues anyway: for that reason, the return value is
114 // ignored. To avoid complaints from static code checkers that notice
115 // that the return values from other calls to sigaction() have been
116 // used, the call to sigaction is explicitly cast to void to indicate
117 // that the return value is intentionally being ignored.
118 static_cast<void>(sigaction(sig, &prev_sa, 0));
119 isc_throw(SignalSetError, "onreceipt_handler failed for signal "
120 << sig << ": " << ex.what());
121 }
122
123 // Restore the sig action to re-enable handling this signal.
124 if (sigaction(sig, &prev_sa, 0) < 0) {
125 // Highly unlikely we can get here.
126 const char* errmsg = strerror(errno);
127 isc_throw(SignalSetError, "failed to restore handler for signal "
128 << sig << ": " << errmsg);
129 }
130
131 return (signal_processed);
132 }
133
134 SignalSet::SignalSet(const int sig0) {
135 // Copy static pointers to ensure they don't lose scope before we do.
136 registered_signals_ = getRegisteredSignals();
137 signal_states_ = getSignalStates();
138 add(sig0);
139 }
140
141 SignalSet::SignalSet(const int sig0, const int sig1) {
142 registered_signals_ = getRegisteredSignals();
143 signal_states_ = getSignalStates();
144 add(sig0);
145 add(sig1);
146 }
147
148 SignalSet::SignalSet(const int sig0, const int sig1, const int sig2) {
149 registered_signals_ = getRegisteredSignals();
150 signal_states_ = getSignalStates();
151 add(sig0);
152 add(sig1);
153 add(sig2);
154 }
155
156 SignalSet::~SignalSet() {
157 // Set default signal handlers.
158 try {
159 clear();
160 } catch (...) {
161 // Not a good thing to throw from a destructor. in fact this should
162 // not throw an exception because we just unregister the signals
163 // that we have previously registered. So the signal codes are fine.
164 }
165 }
166
167 void
168 SignalSet::add(const int sig) {
169 insert(sig);
170 struct sigaction sa;
171 memset(&sa, 0, sizeof(sa));
172 sa.sa_handler = internalHandler;
173 sigfillset(&sa.sa_mask);
174 if (sigaction(sig, &sa, 0) < 0) {
175 const char* errmsg = strerror(errno);
176 erase(sig);
177 isc_throw(SignalSetError, "failed to register a signal handler for"
178 " signal " << sig << ": " << errmsg);
179 }
180 }
181
182 void
183 SignalSet::block() const {
184 maskSignals(SIG_BLOCK);
185 }
186
187 void
188 SignalSet::clear() {
189 // Iterate over a copy of the registered signal set because the
190 // remove function is erasing the elements and we don't want to
191 // erase the elements we are iterating over. This would cause
192 // a segfault.
193 std::set<int> all_signals = local_signals_;
194 for (std::set<int>::const_iterator it = all_signals.begin();
195 it != all_signals.end(); ++it) {
196 remove(*it);
197 }
198 }
199
200 int
201 SignalSet::getNext() const {
202 for (std::list<int>::iterator it = signal_states_->begin();
203 it != signal_states_->end(); ++it) {
204 if (local_signals_.find(*it) != local_signals_.end()) {
205 return (*it);
206 }
207 }
208 return (-1);
209 }
210
211 void
212 SignalSet::erase(const int sig) {
213 if (local_signals_.find(sig) == local_signals_.end()) {
214 isc_throw(SignalSetError, "failed to unregister signal " << sig
215 << " from a signal set: signal is not owned by the"
216 " signal set");
217 }
218 // Remove globally registered signal.
219 registered_signals_->erase(sig);
220 // Remove unhandled signals from the queue.
221 for (std::list<int>::iterator it = signal_states_->begin();
222 it != signal_states_->end(); ++it) {
223 if (*it == sig) {
224 it = signal_states_->erase(it);
225 }
226 }
227
228 // Remove locally registered signal.
229 local_signals_.erase(sig);
230 }
231
232 void
233 SignalSet::handleNext(SignalHandler signal_handler) {
234 block();
235 int signum = getNext();
236 if (signum >= 0) {
237 popNext();
238 try {
239 signal_handler(signum);
240 } catch (...) {
241 unblock();
242 throw;
243 }
244 }
245 unblock();
246 }
247
248 void
249 SignalSet::insert(const int sig) {
250 if ((registered_signals_->find(sig) != registered_signals_->end()) ||
251 (local_signals_.find(sig) != local_signals_.end())) {
252 isc_throw(SignalSetError, "attempt to register a duplicate signal "
253 << sig);
254 }
255 registered_signals_->insert(sig);
256 local_signals_.insert(sig);
257 }
258
259 void
260 SignalSet::maskSignals(const int mask) const {
261 sigset_t new_set;
262 sigemptyset(&new_set);
263 for (std::set<int>::const_iterator it = registered_signals_->begin();
264 it != registered_signals_->end(); ++it) {
265 sigaddset(&new_set, *it);
266 }
267 pthread_sigmask(mask, &new_set, 0);
268 }
269
270 void
271 SignalSet::popNext() {
272 for (std::list<int>::iterator it = signal_states_->begin();
273 it != signal_states_->end(); ++it) {
274 if (local_signals_.find(*it) != local_signals_.end()) {
275 signal_states_->erase(it);
276 return;
277 }
278 }
279 }
280
281 void
282 SignalSet::remove(const int sig) {
283 // Unregister only if we own this signal.
284 if (local_signals_.find(sig) != local_signals_.end()) {
285 struct sigaction sa;
286 memset(&sa, 0, sizeof(sa));
287 sa.sa_handler = SIG_DFL;
288 sigfillset(&sa.sa_mask);
289 if (sigaction(sig, &sa, 0) < 0) {
290 isc_throw(SignalSetError, "unable to restore original signal"
291 " handler for signal: " << sig);
292 }
293 erase(sig);
294 } else {
295 isc_throw(SignalSetError, "failed to unregister signal " << sig
296 << ": this signal is not owned by the signal set");
297 }
298 }
299
300 void
301 SignalSet::unblock() const {
302 maskSignals(SIG_UNBLOCK);
303 }
304
305
306 void
307 SignalSet::setOnReceiptHandler(BoolSignalHandler handler) {
308 onreceipt_handler_ = handler;
309 }
310
311 void
312 SignalSet::clearOnReceiptHandler() {
313 onreceipt_handler_ = BoolSignalHandler();
314 }
315
316 } // end of isc::util
317 } // end of isc
isc::util::SignalSet::clearOnReceiptHandler
static void clearOnReceiptHandler()
Unregisters the onreceipt signal handler.
Definition: signal_set.cc:312
isc::util::BoolSignalHandler
boost::function< bool(int signum)> BoolSignalHandler
Pointer to a signal handling function which returns bool result.
Definition: signal_set.h:54
isc::util::SignalSet::remove
void remove(const int sig)
Uninstalls signal handler for a specified signal.
Definition: signal_set.cc:282
isc::util::SignalSet::getNext
int getNext() const
Returns a code of the next received signal.
Definition: signal_set.cc:201
signal_set.h
isc::util::SigIntSet
std::set< int > SigIntSet
Defines a set of integer signal identifiers: SIGHUP, SIGTERM...
Definition: signal_set.h:32
isc::util::SignalSet::~SignalSet
~SignalSet()
Destructor.
Definition: signal_set.cc:156
isc::util::SigIntListPtr
boost::shared_ptr< SigIntList > SigIntListPtr
Pointer to a list of signal identifiers.
Definition: signal_set.h:39
isc::util::SignalHandler
boost::function< void(int signum)> SignalHandler
Pointer to the signal handling function.
Definition: signal_set.h:47
isc::util
Definition: edns.h:19
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::util::SignalSet::add
void add(const int sig)
Installs the handler for the specified signal.
Definition: signal_set.cc:168
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::util::SignalSet::SignalSet
SignalSet(const int sig0)
Constructor installing one signal.
Definition: signal_set.cc:134
isc::util::SignalSet::setOnReceiptHandler
static void setOnReceiptHandler(BoolSignalHandler handler)
Registers a handler as the onreceipt signal handler.
Definition: signal_set.cc:307
isc::util::SignalSet::clear
void clear()
Uninstalls all signals.
Definition: signal_set.cc:188
isc::util::SignalSetError
Exception thrown when the isc::util::SignalSet class experiences an error.
Definition: signal_set.h:24
isc::util::SignalSet::invokeOnReceiptHandler
static bool invokeOnReceiptHandler(int sig)
Invokes the onreceipt handler if it exists.
Definition: signal_set.cc:88
isc::util::SigIntList
std::list< int > SigIntList
Defines a list of integer signal identifiers: SIGHUP, SIGTERM...
Definition: signal_set.h:37
isc::util::SigIntSetPtr
boost::shared_ptr< SigIntSet > SigIntSetPtr
Pointer to a set of signal identifiers.
Definition: signal_set.h:34
isc::util::SignalSet::handleNext
void handleNext(SignalHandler signal_handler)
Calls a handler for the next received signal.
Definition: signal_set.cc:233