You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

service.hpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // \file service.hpp
  2. //
  3. // Copyright (C) 2014 MicroNeil Research Corporation.
  4. //
  5. // This program is part of the MicroNeil Research Open Library Project. For
  6. // more information go to http://www.microneil.com/OpenLibrary/index.html
  7. //
  8. // This program is free software; you can redistribute it and/or modify it
  9. // under the terms of the GNU General Public License as published by the
  10. // Free Software Foundation; either version 2 of the License, or (at your
  11. // option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful, but WITHOUT
  14. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. // more details.
  17. //
  18. // You should have received a copy of the GNU General Public License along with
  19. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. // Place, Suite 330, Boston, MA 02111-1307 USA
  21. //==============================================================================
  22. /*
  23. \brief The service module provides a framework for implementing *nix
  24. daemons and Windows services.
  25. */
  26. #ifndef SERVICE_HPP
  27. #define SERVICE_HPP
  28. #ifdef WIN32
  29. #include <windows.h>
  30. #else
  31. #include <chrono>
  32. #endif
  33. #include <string>
  34. #include <vector>
  35. #include <mutex>
  36. #ifdef WIN32
  37. int main(int argc, char *argv[]);
  38. VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
  39. VOID WINAPI ServiceCtrlHandler(DWORD message);
  40. #else
  41. int main(int argc, char *argv[]);
  42. #endif
  43. namespace CodeDweller {
  44. /** Singleton class that implements a daemon (*nix) or service
  45. (Windows).
  46. This class implements a *nix daemon or a Windows service.
  47. To implement a daemon or service, implement the required methods
  48. of this class, and link with service.cpp. When compiled under
  49. *nix, the file service.cpp contains the definition of main for
  50. the *nix daemon. When compiled under Windows, the file
  51. service.cpp contains the entry points for the Windows service.
  52. Nomenclature:
  53. <ol>
  54. <li>Service is a *nix daemon or Windows service.</li>
  55. <li>Message is a posix signal or Windows message. This class
  56. supports the following messages:
  57. <ol>
  58. <li>Pause. This is the posix TSTP signal or Windows Pause
  59. message. This instructs the service to temporarily stop
  60. running.</li>
  61. <li>Resume. This is the posix CONT signal or Windows
  62. Resume message. This instructs the service to resume
  63. running after receiving a Pause message. If the service
  64. isn't temporarily stopped after receiving a Pause message,
  65. the Resume message has no effect.</li>
  66. <li>Stop. This is the posix TERM signal or Windows Stop
  67. or Shutdown message. This instructs the service to shut
  68. down and exit.</li>
  69. </ol>
  70. </li>
  71. <li>Callback. This is a function that is executed when a
  72. message is received.</li>
  73. </ol>
  74. */
  75. class Service
  76. {
  77. public:
  78. /// Callback functor interface.
  79. class Callback {
  80. public:
  81. /// Callback method.
  82. virtual void operator()() = 0;
  83. };
  84. /// Register a callback for receipt of Pause.
  85. //
  86. // \param[in] pauseFunctor is the function object to invoke when
  87. // Pause is received.
  88. //
  89. static void onPauseCall(Callback &pauseFunctor);
  90. /// Register a callback for receipt of Resume.
  91. //
  92. // \param[in] resumeFunctor is the function object to invoke when
  93. // Resume is received.
  94. //
  95. static void onResumeCall(Callback &resumeFunctor);
  96. /// Register a callback for receipt of Stop.
  97. //
  98. // \param[in] stopFunctor is the function object to invoke when
  99. // Stop is received.
  100. //
  101. static void onStopCall(Callback &stopFunctor);
  102. /// Check whether Pause was received.
  103. //
  104. // \returns if the Pause message was received, false otherwise.
  105. //
  106. static bool receivedPause();
  107. /// Check whether Resume was received.
  108. //
  109. // \returns if the Resume message was received, false otherwise.
  110. //
  111. static bool receivedResume();
  112. /// Check whether the last message received was Stop.
  113. //
  114. // \returns true if Stop was the most recent message received,
  115. // false otherwise.
  116. //
  117. static bool receivedStop();
  118. /// Clear receiving the Pause message.
  119. static void clearReceivedPause();
  120. /// Clear receiving the Resume message.
  121. static void clearReceivedResume();
  122. /// Clear receiving the Stop message.
  123. static void clearReceivedStop();
  124. /// Get a reference to the command-line arguments.
  125. //
  126. // \returns a reference to the vector of command-line arguments of
  127. // the application. Index i corresponds to command-line argument
  128. // i.
  129. //
  130. static const std::vector<std::string> &arguments();
  131. /// Set the timeout for executing one Stop callback.
  132. //
  133. // If a Stop callback takes longer than the specified timeout, the
  134. // service aborts.
  135. //
  136. // \param[in] timeout_ms is the timeout in milliseconds. If a
  137. // value less than 1 is specified, a value of 1 is used.
  138. //
  139. static void setStopCallbackTimeout_ms(int timeout_ms);
  140. private:
  141. /// Private constructor prevents instantiation.
  142. Service();
  143. /// Prevent copying.
  144. Service(Service const&) {}
  145. /// Prevent assignment.
  146. void operator=(Service const&) {}
  147. /// Get the instance of the singleton.
  148. //
  149. // \returns a reference to the singleton.
  150. //
  151. static Service& getInstance();
  152. /// Main entry point.
  153. //
  154. // \param[in] argc is the number of arguments.
  155. //
  156. // \param[in] argv is an array of strings containing the
  157. // command-line arguments. The end of the array is indicated by a
  158. // null pointer.
  159. //
  160. // \returns exit code of the service.
  161. //
  162. int main(int argc, char *argv[]);
  163. #ifdef WIN32
  164. /// Service entry point for Windows.
  165. // \param[in] argc is the number of arguments.
  166. //
  167. // \param[in] argv is an array of strings containing the
  168. // command-line arguments. The end of the array is indicated by a
  169. // null pointer.
  170. //
  171. void serviceMain(DWORD argc, LPTSTR *argv);
  172. #endif
  173. /// Load the command-line arguments.
  174. //
  175. // This method loads the object with the command-line parameters.
  176. //
  177. // \param[in] argc is the number of arguments.
  178. //
  179. // \param[in] argv is an array of strings containing the
  180. // command-line arguments. The end of the array is indicated by a
  181. // null pointer.
  182. //
  183. void loadArguments(int argc, char *argv[]);
  184. /// Initialize and run the application.
  185. //
  186. // \returns the exit status of the service.
  187. //
  188. int run();
  189. /// Mutex to serialize access to the object.
  190. static std::mutex objectMutex;
  191. #ifdef WIN32
  192. /// Process a control message.
  193. //
  194. // \param[in] message is the message to process.
  195. //
  196. void processCtrlMessage(DWORD message);
  197. #else
  198. /// Thread start function to receive and process messages.
  199. void processMessages();
  200. #endif
  201. /// Thread start function for the watchdog thread.
  202. //
  203. // This thread sleeps until timeoutTime, and then causes the
  204. // process to exit.
  205. void watchdog();
  206. /// Command-line arguments.
  207. static std::vector<std::string> cmdLineArgs;
  208. /// True if Pause message was received.
  209. static bool pauseReceived;
  210. /// True if Resume message was received.
  211. static bool resumeReceived;
  212. /// True if Stop message was received.
  213. static bool stopReceived;
  214. /// Functions to invoke when the Pause is received.
  215. static std::vector<Callback *> pauseCallbacks;
  216. /// Functions to invoke when the Resume is received.
  217. static std::vector<Callback *> resumeCallbacks;
  218. /// Functions to invoke when the Stop is received.
  219. static std::vector<Callback *> stopCallbacks;
  220. /// Stop message callback timeout.
  221. static int stopCallbackTimeout_ms;
  222. /// Absolute time at which the Stop callback timeout expires.
  223. std::chrono::time_point<std::chrono::steady_clock> timeoutTime;
  224. /// True if the Stop callbacks are being invoked.
  225. bool stopCallbacksActive;
  226. #ifdef WIN32
  227. /// Status of the service.
  228. SERVICE_STATUS serviceStatus;
  229. /// Handle for accessing service status on the OS.
  230. SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
  231. friend int ::main(int argc, char *argv[]);
  232. friend VOID WINAPI ::ServiceMain(DWORD argc, LPTSTR *argv);
  233. friend VOID WINAPI ::ServiceCtrlHandler(DWORD message);
  234. #else
  235. /// Set of signals to wait for.
  236. sigset_t signalSet;
  237. friend int ::main(int argc, char *argv[]);
  238. #endif
  239. };
  240. }
  241. #endif // SERVICE_HPP