signal_set.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <util/io/signal_set.h>
  15. #include <list>
  16. using namespace isc;
  17. using namespace isc::util::io;
  18. namespace {
  19. /// @brief Returns a pointer to the global set of registered signals.
  20. ///
  21. /// Multiple instances of @c SignalSet may use this pointer to access
  22. /// and update the set.
  23. ///
  24. /// @return Pointer to the global set of registered signals. This pointer
  25. /// is always initialized and points to a valid object.
  26. std::set<int>* getRegisteredSignals() {
  27. static std::set<int> registered_signals;
  28. return (&registered_signals);
  29. }
  30. /// @brief Returns a pointer to static collection of signals received.
  31. ///
  32. /// Multiple instances of @c SignalSet may use this pointer to access
  33. /// and update the queue of signals received.
  34. ///
  35. /// @return Static collection of signals received. This pointer is always
  36. /// initialized and points to a valid object.
  37. std::list<int>* getSignalStates() {
  38. static std::list<int> states;
  39. return (&states);
  40. }
  41. /// @brief Internal signal handler for @c isc::util::io::SignalSet class.
  42. ///
  43. /// This signal handler adds a signal number for which it is being
  44. /// invoked to the queue of received signals. It prevents adding duplicated
  45. /// signals. All duplicated signals are dropped. This prevents hammering
  46. /// a process to invoke handlers (e.g. DHCP server reconfiguration), when
  47. /// many the same signals are received one after another.
  48. ///
  49. /// @param sig Signal number.
  50. void internalHandler(int sig) {
  51. std::list<int>* states = getSignalStates();
  52. for (std::list<int>::const_iterator it = states->begin();
  53. it != states->end(); ++it) {
  54. if (sig == *it) {
  55. return;
  56. }
  57. }
  58. states->push_back(sig);
  59. }
  60. }
  61. namespace isc {
  62. namespace util {
  63. namespace io {
  64. SignalSet::SignalSet(const int sig0) {
  65. add(sig0);
  66. }
  67. SignalSet::SignalSet(const int sig0, const int sig1) {
  68. add(sig0);
  69. add(sig1);
  70. }
  71. SignalSet::SignalSet(const int sig0, const int sig1, const int sig2) {
  72. add(sig0);
  73. add(sig1);
  74. add(sig2);
  75. }
  76. SignalSet::~SignalSet() {
  77. // Set default signal handlers.
  78. try {
  79. clear();
  80. } catch (...) {
  81. // Not a good thing to throw from a destructor. in fact this should
  82. // not throw an exception because we just unregister the signals
  83. // that we have previously registered. So the signal codes are fine.
  84. }
  85. }
  86. void
  87. SignalSet::add(const int sig) {
  88. insert(sig);
  89. struct sigaction sa;
  90. sa.sa_handler = internalHandler;
  91. if (sigaction(sig, &sa, 0) < 0) {
  92. erase(sig);
  93. isc_throw(SignalSetError, "failed to register a signal handler for"
  94. " signal " << sig << ": " << strerror(errno));
  95. }
  96. }
  97. void
  98. SignalSet::clear() {
  99. // Iterate over a copy of the registered signal set because the
  100. // remove function is erasing the elements and we don't want to
  101. // erase the elements we are iterating over. This would cause
  102. // a segfault.
  103. std::set<int> all_signals = local_signals_;
  104. for (std::set<int>::const_iterator it = all_signals.begin();
  105. it != all_signals.end(); ++it) {
  106. remove(*it);
  107. }
  108. }
  109. int
  110. SignalSet::getNext() const {
  111. std::list<int>* states = getSignalStates();
  112. for (std::list<int>::iterator it = states->begin();
  113. it != states->end(); ++it) {
  114. if (local_signals_.find(*it) != local_signals_.end()) {
  115. return (*it);
  116. }
  117. }
  118. return (-1);
  119. }
  120. void
  121. SignalSet::erase(const int sig) {
  122. if (local_signals_.find(sig) == local_signals_.end()) {
  123. isc_throw(SignalSetError, "failed to unregister signal " << sig
  124. << " from a signal set: signal is not owned by the"
  125. " signal set");
  126. }
  127. // Remove globally registered signal.
  128. getRegisteredSignals()->erase(sig);
  129. // Remove unhandled signals from the queue.
  130. for (std::list<int>::iterator it = getSignalStates()->begin();
  131. it != getSignalStates()->end(); ++it) {
  132. if (*it == sig) {
  133. it = getSignalStates()->erase(it);
  134. }
  135. }
  136. // Remove locally registered signal.
  137. local_signals_.erase(sig);
  138. }
  139. void
  140. SignalSet::handleNext(SignalHandler signal_handler) {
  141. block();
  142. int signum = getNext();
  143. if (signum >= 0) {
  144. popNext();
  145. try {
  146. signal_handler(signum);
  147. } catch (...) {
  148. unblock();
  149. throw;
  150. }
  151. }
  152. unblock();
  153. }
  154. void
  155. SignalSet::insert(const int sig) {
  156. std::set<int>* global_signals = getRegisteredSignals();
  157. if ((global_signals->find(sig) != global_signals->end()) ||
  158. (local_signals_.find(sig) != local_signals_.end())) {
  159. isc_throw(SignalSetError, "attempt to register a duplicate signal "
  160. << sig);
  161. }
  162. global_signals->insert(sig);
  163. local_signals_.insert(sig);
  164. }
  165. void
  166. SignalSet::maskSignals(const int mask) const {
  167. sigset_t new_set;
  168. for (std::set<int>::const_iterator it = getRegisteredSignals()->begin();
  169. it != getRegisteredSignals()->end(); ++it) {
  170. sigaddset(&new_set, *it);
  171. }
  172. sigprocmask(mask, &new_set, 0);
  173. }
  174. void
  175. SignalSet::popNext() {
  176. std::list<int>* states = getSignalStates();
  177. for (std::list<int>::iterator it = states->begin();
  178. it != states->end(); ++it) {
  179. if (local_signals_.find(*it) != local_signals_.end()) {
  180. states->erase(it);
  181. return;
  182. }
  183. }
  184. }
  185. void
  186. SignalSet::remove(const int sig) {
  187. // Unregister only if we own this signal.
  188. if (local_signals_.find(sig) != local_signals_.end()) {
  189. struct sigaction sa;
  190. sa.sa_handler = SIG_DFL;
  191. if (sigaction(sig, &sa, 0) < 0) {
  192. isc_throw(SignalSetError, "unable to restore original signal"
  193. " handler for signal: " << sig);
  194. }
  195. erase(sig);
  196. } else {
  197. isc_throw(SignalSetError, "failed to unregister signal " << sig
  198. << ": this signal is not owned by the signal set");
  199. }
  200. }
  201. } // end of isc::util::io
  202. } // end of isc::util
  203. } // end of isc