Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
  29. #ifndef WIN32
  30. #define WIN32
  31. #endif
  32. #endif
  33. #ifdef WIN32
  34. #include <windows.h>
  35. #else
  36. #include <chrono>
  37. #endif
  38. #include <string>
  39. #include <vector>
  40. #include <mutex>
  41. #ifdef WIN32
  42. int main(int argc, char *argv[]);
  43. VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
  44. VOID WINAPI ServiceCtrlHandler(DWORD message);
  45. #else
  46. int main(int argc, char *argv[]);
  47. #endif
  48. namespace CodeDweller {
  49. /** Singleton class that implements a daemon (*nix) or service
  50. (Windows).
  51. This class implements a *nix daemon or a Windows service.
  52. To implement a daemon or service, implement the required methods
  53. of this class, and link with service.cpp. When compiled under
  54. *nix, the file service.cpp contains the definition of main for
  55. the *nix daemon. When compiled under Windows, the file
  56. service.cpp contains the entry points for the Windows service.
  57. Nomenclature:
  58. <ol>
  59. <li>Service is a *nix daemon or Windows service.</li>
  60. <li>Message is a posix signal or Windows message. This class
  61. supports the following messages:
  62. <ol>
  63. <li>Pause. This is the posix TSTP signal or Windows Pause
  64. message. This instructs the service to temporarily stop
  65. running.</li>
  66. <li>Resume. This is the posix CONT signal or Windows
  67. Resume message. This instructs the service to resume
  68. running after receiving a Pause message. If the service
  69. isn't temporarily stopped after receiving a Pause message,
  70. the Resume message has no effect.</li>
  71. <li>Stop. This is the posix TERM signal or Windows Stop
  72. or Shutdown message. This instructs the service to shut
  73. down and exit.</li>
  74. </ol>
  75. </li>
  76. <li>Callback. This is a function that is executed when a
  77. message is received.</li>
  78. </ol>
  79. */
  80. class Service
  81. {
  82. public:
  83. /// Callback functor interface.
  84. class Callback {
  85. public:
  86. /// Callback method.
  87. virtual void operator()() = 0;
  88. };
  89. /// Register a callback for receipt of Pause.
  90. //
  91. // \param[in] pauseFunctor is the function object to invoke when
  92. // Pause is received.
  93. //
  94. static void onPauseCall(Callback &pauseFunctor);
  95. /// Register a callback for receipt of Resume.
  96. //
  97. // \param[in] resumeFunctor is the function object to invoke when
  98. // Resume is received.
  99. //
  100. static void onResumeCall(Callback &resumeFunctor);
  101. /// Register a callback for receipt of Stop.
  102. //
  103. // \param[in] stopFunctor is the function object to invoke when
  104. // Stop is received.
  105. //
  106. static void onStopCall(Callback &stopFunctor);
  107. /// Check whether Pause was received.
  108. //
  109. // \returns if the Pause message was received, false otherwise.
  110. //
  111. static bool receivedPause();
  112. /// Check whether Resume was received.
  113. //
  114. // \returns if the Resume message was received, false otherwise.
  115. //
  116. static bool receivedResume();
  117. /// Check whether the last message received was Stop.
  118. //
  119. // \returns true if Stop was the most recent message received,
  120. // false otherwise.
  121. //
  122. static bool receivedStop();
  123. /// Clear receiving the Pause message.
  124. static void clearReceivedPause();
  125. /// Clear receiving the Resume message.
  126. static void clearReceivedResume();
  127. /// Clear receiving the Stop message.
  128. static void clearReceivedStop();
  129. /// Get a reference to the command-line arguments.
  130. //
  131. // \returns a reference to the vector of command-line arguments of
  132. // the application. Index i corresponds to command-line argument
  133. // i.
  134. //
  135. static const std::vector<std::string> &arguments();
  136. /// Set the timeout for executing one Stop callback.
  137. //
  138. // If a Stop callback takes longer than the specified timeout, the
  139. // service aborts.
  140. //
  141. // \param[in] timeout_ms is the timeout in milliseconds. If a
  142. // value less than 1 is specified, a value of 1 is used.
  143. //
  144. static void setStopCallbackTimeout_ms(int timeout_ms);
  145. private:
  146. /// Private constructor prevents instantiation.
  147. Service();
  148. /// Prevent copying.
  149. Service(Service const&) {}
  150. /// Prevent assignment.
  151. void operator=(Service const&) {}
  152. /// Get the instance of the singleton.
  153. //
  154. // \returns a reference to the singleton.
  155. //
  156. static Service& getInstance();
  157. /// Main entry point.
  158. //
  159. // \param[in] argc is the number of arguments.
  160. //
  161. // \param[in] argv is an array of strings containing the
  162. // command-line arguments. The end of the array is indicated by a
  163. // null pointer.
  164. //
  165. // \returns exit code of the service.
  166. //
  167. int main(int argc, char *argv[]);
  168. #ifdef WIN32
  169. /// Service entry point for Windows.
  170. // \param[in] argc is the number of arguments.
  171. //
  172. // \param[in] argv is an array of strings containing the
  173. // command-line arguments. The end of the array is indicated by a
  174. // null pointer.
  175. //
  176. void serviceMain(DWORD argc, LPTSTR *argv);
  177. #endif
  178. /// Load the command-line arguments.
  179. //
  180. // This method loads the object with the command-line parameters.
  181. //
  182. // \param[in] argc is the number of arguments.
  183. //
  184. // \param[in] argv is an array of strings containing the
  185. // command-line arguments. The end of the array is indicated by a
  186. // null pointer.
  187. //
  188. void loadArguments(int argc, char *argv[]);
  189. /// Initialize and run the application.
  190. //
  191. // \returns the exit status of the service.
  192. //
  193. int run();
  194. /// Mutex to serialize access to the object.
  195. static std::mutex objectMutex;
  196. #ifdef WIN32
  197. /// Process a control message.
  198. //
  199. // \param[in] message is the message to process.
  200. //
  201. void processCtrlMessage(DWORD message);
  202. #else
  203. /// Thread start function to receive and process messages.
  204. void processMessages();
  205. #endif
  206. /// Thread start function for the watchdog thread.
  207. //
  208. // This thread sleeps until timeoutTime, and then causes the
  209. // process to exit.
  210. void watchdog();
  211. /// Command-line arguments.
  212. static std::vector<std::string> cmdLineArgs;
  213. /// True if Pause message was received.
  214. static bool pauseReceived;
  215. /// True if Resume message was received.
  216. static bool resumeReceived;
  217. /// True if Stop message was received.
  218. static bool stopReceived;
  219. /// Functions to invoke when the Pause is received.
  220. static std::vector<Callback *> pauseCallbacks;
  221. /// Functions to invoke when the Resume is received.
  222. static std::vector<Callback *> resumeCallbacks;
  223. /// Functions to invoke when the Stop is received.
  224. static std::vector<Callback *> stopCallbacks;
  225. /// Stop message callback timeout.
  226. static int stopCallbackTimeout_ms;
  227. /// Absolute time at which the Stop callback timeout expires.
  228. std::chrono::time_point<std::chrono::steady_clock> timeoutTime;
  229. /// True if the Stop callbacks are being invoked.
  230. bool stopCallbacksActive;
  231. #ifdef WIN32
  232. /// Status of the service.
  233. SERVICE_STATUS serviceStatus;
  234. /// Handle for accessing service status on the OS.
  235. SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
  236. friend int ::main(int argc, char *argv[]);
  237. friend VOID WINAPI ::ServiceMain(DWORD argc, LPTSTR *argv);
  238. friend VOID WINAPI ::ServiceCtrlHandler(DWORD message);
  239. #else
  240. /// Set of signals to wait for.
  241. sigset_t signalSet;
  242. friend int ::main(int argc, char *argv[]);
  243. #endif
  244. };
  245. }
  246. #endif // SERVICE_HPP