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) {
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
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 
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
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
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
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
308  onreceipt_handler_ = handler;
309 }
310 
311 void
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