signal_set.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright (C) 2014, 2015 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. #ifndef SIGNAL_SET_H
  15. #define SIGNAL_SET_H
  16. #include <exceptions/exceptions.h>
  17. #include <boost/function.hpp>
  18. #include <boost/noncopyable.hpp>
  19. #include <boost/shared_ptr.hpp>
  20. #include <set>
  21. #include <list>
  22. #include <signal.h>
  23. namespace isc {
  24. namespace util {
  25. /// @brief Exception thrown when the @c isc::util::SignalSet class
  26. /// experiences an error.
  27. class SignalSetError : public Exception {
  28. public:
  29. SignalSetError(const char* file, size_t line, const char* what) :
  30. isc::Exception(file, line, what) { };
  31. };
  32. /// @brief Defines a set of integer signal identifiers: SIGHUP, SIGTERM...
  33. typedef std::set<int> SigIntSet;
  34. /// @brief Pointer to a set of signal identifiers
  35. typedef boost::shared_ptr<SigIntSet> SigIntSetPtr;
  36. /// @brief Defines a list of integer signal identifiers: SIGHUP, SIGTERM...
  37. typedef std::list<int> SigIntList;
  38. /// @brief Pointer to a list of signal identifiers
  39. typedef boost::shared_ptr<SigIntList> SigIntListPtr;
  40. /// @brief Forward declaration to the @c isc::util::SignalSet.
  41. class SignalSet;
  42. /// @brief Pointer to the @c isc::util::SignalSet.
  43. typedef boost::shared_ptr<SignalSet> SignalSetPtr;
  44. /// @brief Pointer to the signal handling function.
  45. typedef boost::function<void(int signum)> SignalHandler;
  46. /// @brief Pointer to a signal handling function which returns bool result.
  47. ///
  48. /// The handler is expected to return true if the signal it was given has
  49. /// been processed (i.e. should not be recorded for deferred processing) or
  50. /// false in which case it will be recorded.
  51. typedef boost::function<bool(int signum)> BoolSignalHandler;
  52. /// @brief Represents a collection of signals handled in a customized way.
  53. ///
  54. /// Kea processes must handle selected signals in a specialized way. For
  55. /// example: SIGINT and SIGTERM must perform a graceful shut down of the
  56. /// server. The SIGHUP signal is used to trigger server's reconfiguration.
  57. ///
  58. /// This class allows the caller to register one or more signals to catch
  59. /// and process. Signals may be handled either immediately upon arrival and/or
  60. /// recorded and processed later. To process signals immediately, the caller
  61. /// must register an "on-receipt" handler. This handler is expected to return
  62. /// a true or false indicating whether or not the signal has been processed.
  63. /// Signal occurrences that are not processed by the on-receipt handler are
  64. /// remembered by SignalSet for deferred processing. The caller can then query
  65. /// SignalSet at their discretion to determine if any signal occurrences are
  66. /// pending and process them.
  67. ///
  68. /// SignalSet uses an internal handler to catch all registered signals. When
  69. /// a signal arrives the internal handler will first attempt to invoke the
  70. /// on-receipt handler. If one has been registered it is passed the
  71. /// signal value as an argument and if it returns true upon completion, the
  72. /// internal handler will exit without further action. If the on-receipt
  73. /// handler returned false or one is not registered, then internal handler
  74. /// will record the signal value for deferred processing. Note that once a
  75. /// particular signal has been recorded, any further occurrences of that signal
  76. /// will be discarded until the original occurrence has been processed. This
  77. /// guards against rapid-fire occurrences of the same signal.
  78. ///
  79. /// @note This class is not thread safe. It uses static variables and
  80. /// functions to track a global state of signal registration and received
  81. /// signals' queue.
  82. class SignalSet : public boost::noncopyable {
  83. public:
  84. /// @brief Constructor installing one signal.
  85. ///
  86. /// @param sig0 First signal.
  87. /// @throw SignalSetError If attempting to add duplicated signal or
  88. /// the signal is invalid.
  89. SignalSet(const int sig0);
  90. /// @brief Constructor installing two signals.
  91. ///
  92. /// @param sig0 First signal.
  93. /// @param sig1 Second signal.
  94. /// @throw SignalSetError If attempting to add duplicated signal or
  95. /// the signal is invalid.
  96. SignalSet(const int sig0, const int sig1);
  97. /// @brief Constructor installing three signals.
  98. ///
  99. /// @param sig0 First signal.
  100. /// @param sig1 Second signal.
  101. /// @param sig2 Third signal.
  102. /// @throw SignalSetError If attempting to add duplicated signal or
  103. /// the signal is invalid.
  104. SignalSet(const int sig0, const int sig1, const int sig2);
  105. /// @brief Destructor.
  106. ///
  107. /// Removes installed handlers.
  108. ~SignalSet();
  109. /// @brief Installs the handler for the specified signal.
  110. ///
  111. /// This function adds a signal to the set. When the signal is received
  112. /// by the process, it will be recorded and a signal can be later handled
  113. /// by the process.
  114. ///
  115. /// @param sig Signal code.
  116. /// @throw SignalSetError if signal being added duplicates an existing
  117. /// signal.
  118. void add(const int sig);
  119. /// @brief Uninstalls all signals.
  120. ///
  121. /// This function calls @c isc::util::SignalSet::remove for each
  122. /// installed signal.
  123. void clear();
  124. /// @brief Returns a code of the next received signal.
  125. ///
  126. /// @return A code of the next received signal or -1 if there are no
  127. /// more signals received.
  128. int getNext() const;
  129. /// @brief Calls a handler for the next received signal.
  130. ///
  131. /// This function handles the next received signal and removes it from the
  132. /// queue of received signals. While the function is executed, all custom
  133. /// signal handlers are blocked to prevent race condition.
  134. ///
  135. /// @param signal_handler A pointer to the signal handler function to
  136. /// be used to handle the signal.
  137. void handleNext(SignalHandler signal_handler);
  138. /// @brief Uninstalls signal handler for a specified signal.
  139. ///
  140. /// @param sig A code of the signal to be removed.
  141. void remove(const int sig);
  142. /// @brief Registers a handler as the onreceipt signal handler
  143. ///
  144. /// Sets the given handler as the handler to invoke immediately
  145. /// upon receipt of a a registered signal.
  146. ///
  147. /// @note Currently, the on-receipt handler is stored as a static
  148. /// value and hence there may only be one such handler at a time
  149. /// for a given process.
  150. ///
  151. /// @param handler the signal handler to register
  152. static void setOnReceiptHandler(BoolSignalHandler handler);
  153. /// @brief Unregisters the onreceipt signal handler
  154. static void clearOnReceiptHandler();
  155. /// @brief Invokes the onreceipt handler if it exists
  156. ///
  157. /// This static method is used by @c isc::util::SignalSet class to
  158. /// invoke the registered handler (if one) immediately upon receipt of
  159. /// a registered signal.
  160. ///
  161. /// Prior to invoking the handler, it sets signal action for the
  162. /// given signal to SIG_IGN which prevents any repeat signal
  163. /// occurrences from queuing while the handler is executing. Upon
  164. /// completion of the handler, the signal action is restored which
  165. /// re-enables receipt and handling of the signal.
  166. ///
  167. /// @param sig Signal number.
  168. /// @return Boolean false if no on-receipt handler was registered,
  169. /// otherwise it is the value returned by the on-receipt handler.
  170. static bool invokeOnReceiptHandler(int sig);
  171. private:
  172. /// @brief Blocks signals in the set.
  173. ///
  174. /// This function blocks the signals in a set to prevent race condition
  175. /// between the signal handler and the new signal coming in.
  176. void block() const;
  177. /// @brief Removes the signal from the set.
  178. ///
  179. /// This function removes only a signal which is owned by this signal set.
  180. ///
  181. /// @param sig Signal to be removed.
  182. /// @throw SignalSetError if the signal being removed is not owned by this
  183. /// signal set.
  184. void erase(const int sig);
  185. /// @brief Insert a signal to the set.
  186. ///
  187. /// @param sig Signal to be inserted.
  188. /// @throw SignalSetError if a signal being inserted has already been
  189. /// registered in this or other signal set.
  190. void insert(const int sig);
  191. /// @brief Applies a mask to all signals in the set.
  192. ///
  193. /// This function is used by @c SignalSet::block and @c SignalSet::unblock
  194. /// to apply the SIG_BLOCK and SIG_UNBLOCK mask to signals.
  195. ///
  196. /// @param mask A mask to be applied to all signals.
  197. void maskSignals(const int mask) const;
  198. /// @brief Pops a next signal number from the static collection of signals.
  199. ///
  200. /// The static collection of signals is updated by the internal signal
  201. /// handler being invoked when one of the installed signals is received by
  202. /// the process. This function removes the first element of the collection.
  203. void popNext();
  204. /// @brief Unblocks signals in the set.
  205. ///
  206. /// This function unblocks the signals in a set.
  207. void unblock() const;
  208. /// @brief Stores the set of signals registered in this signal set.
  209. std::set<int> local_signals_;
  210. /// @brief Shared pointer to static set of registered signals
  211. /// Set during construction to ensure static set does not lose scope
  212. /// before we do.
  213. SigIntSetPtr registered_signals_;
  214. /// @brief Shared pointer to static list of pending signals
  215. /// Set during construction to ensure static list does not lose scope
  216. /// before we do.
  217. SigIntListPtr signal_states_;
  218. };
  219. }
  220. }
  221. #endif // SIGNAL_SET_H