diff --git a/Util/include/Poco/Util/ServerApplication.h b/Util/include/Poco/Util/ServerApplication.h index f575963da..16fdfb6fc 100644 --- a/Util/include/Poco/Util/ServerApplication.h +++ b/Util/include/Poco/Util/ServerApplication.h @@ -24,6 +24,7 @@ #if defined(POCO_OS_FAMILY_WINDOWS) #include "Poco/NamedEvent.h" #endif +#include namespace Poco { @@ -122,8 +123,20 @@ class Util_API ServerApplication: public Application /// --pidfile=/var/run/sample.pid) may be useful to record the process ID of /// the daemon in a file. The PID file will be removed when the daemon process /// terminates (but not, if it crashes). + /// + /// An application can register a callback to be called at termination time. + /// An example of the termination callback registration at some point + /// during the ServerApplication initialization time: + /// + /// auto tCB = [](const std::string& message) + /// { + /// std::cout << message << std::endl; + /// }; + /// ServerApplication::registerTerminateCallback(tCB, "custom termination message"s); { public: + using TerminateCallback = std::function; + ServerApplication(); /// Creates the ServerApplication. @@ -158,6 +171,12 @@ public: /// waitForTerminationRequest(), this method will return /// and the application can shut down. + static void registerTerminateCallback(TerminateCallback tCB, + const std::string& message = _terminateMessage); + /// Registers a termination callback. + /// Used to register a function to be executed when the system + /// shutdown starts. + protected: int run(); void waitForTerminationRequest(); @@ -207,6 +226,11 @@ private: static SERVICE_STATUS_HANDLE _serviceStatusHandle; static Poco::NamedEvent _terminate; #endif + + static void terminateCallback(); + inline static std::atomic _terminationGuard = false; + inline static TerminateCallback _terminateCallback = nullptr; + inline static std::string _terminateMessage = "System terminating now!"; }; diff --git a/Util/src/ServerApplication.cpp b/Util/src/ServerApplication.cpp index e7d72c99d..1a20db58b 100644 --- a/Util/src/ServerApplication.cpp +++ b/Util/src/ServerApplication.cpp @@ -91,8 +91,22 @@ int ServerApplication::run() } +void ServerApplication::terminateCallback() +{ + if (!_terminationGuard.exchange(true)) + { + if (_terminateCallback) + { + _terminateCallback(_terminateMessage); + _terminateCallback = nullptr; + } + } +} + + void ServerApplication::terminate() { + terminateCallback(); #if defined(POCO_OS_FAMILY_WINDOWS) _terminate.set(); #elif defined(POCO_VXWORKS) || POCO_OS == POCO_OS_ANDROID @@ -103,6 +117,13 @@ void ServerApplication::terminate() } +void ServerApplication::registerTerminateCallback(TerminateCallback tCB, const std::string& message) +{ + _terminateCallback = tCB; + _terminateMessage = message; +} + + #if defined(POCO_OS_FAMILY_WINDOWS) @@ -196,6 +217,7 @@ void ServerApplication::waitForTerminationRequest() { SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); _terminate.wait(); + terminateCallback(); _terminated.set(); } @@ -444,6 +466,7 @@ void ServerApplication::handleStartup(const std::string& name, const std::string void ServerApplication::waitForTerminationRequest() { _terminate.wait(); + terminateCallback(); } @@ -503,8 +526,10 @@ void ServerApplication::waitForTerminationRequest() sigprocmask(SIG_BLOCK, &sset, NULL); int sig; sigwait(&sset, &sig); + terminateCallback(); #else // POCO_OS != POCO_OS_ANDROID _terminate.wait(); + terminateCallback(); #endif }