X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FDaemonTools.hh;h=46d510afda4dcd85007eb9d55d31b88ca7d254ad;hb=498e46942326c504b30ebdbb5e4d9be1b48d2b5f;hp=6ea30e9daaa602787188da3b4943431c993b12a1;hpb=49f2e00bdc4014b34361a0830e7ec365844ee67a;p=senf.git diff --git a/Utils/DaemonTools.hh b/Utils/DaemonTools.hh index 6ea30e9..46d510a 100644 --- a/Utils/DaemonTools.hh +++ b/Utils/DaemonTools.hh @@ -22,18 +22,24 @@ /** \defgroup process Process Management - This collection of utilities provides help in managing daemon processes. + Future features: + + \li Daemon manager watching the real daemon. Auto-restart, when the daemon fails + + \li Provide access to the config console indirectly via the daemon manager. This allows to + connect to the daemon manager console even if the app is not running + + \li For this to be efficient, the daemon manager must be it's own executable (e.g. senf-launch) - \idea Add communication between parent and child process to daemonize() and add things like - init_done(), failure() etc which allow the daemon process to tell the frontend of successful - startup or failure. This probably means moving all the methods into a DaemonTools class (as - statics or via a singleton). This would also allow for automatic pid file creation and - removal (remove in global destructor). + \li auto-detect whether called from senf-launch or not - \idea Add a DaemonProcess baseclass with init() and main() abstract members which wraps the - startup process. DaeminProcess::run() would fork, call init(), create a pid file and then - call main(). Exceptions during init()'s execution would be passed to the parent - process. This is based on the above API. + \li when daemon is running, the console is transparently forwarded to the daemon. The daemon + however can still access the daemon manager as a subgroup + + \li No idea, whether this is sensible: Make the daemon manager completely self-contained (not + dependent on any external OS support) by providing our own log-file rotation support. + + This collection of utilities provides help in managing daemon processes. \idea A closeall()/closemost() function which is useful when starting child processes. We'll use getrlimit to now the biggest filehandle and close all of em. closemost() takes a number of @@ -47,12 +53,172 @@ // Custom includes #include +#include //#include "DaemonTools.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + /** \brief Daemon process + + This class provides the infrastructure to implement robust daemon processes. A daemon + process is implemented by deriving from senf::Daemon and implementing the necessary + (virtual) member functions. + \code + class MyDaemon : public senf::Daemon + { + void configure() { + // Set configuration parameters like daemonize(), pidFile() etc. + } + + void init() { + // Initialize application. Setup all necessary objects. After init() + // has completed, is startup should not fail anymore + } + + void run() { + // Main application code should be called here. + } + }; + \endcode + + The startup procedure is divided into three steps: + \li First, configure() is called. configure() should be as simple as possible. It just needs + to set the daemon parameters. No further setup should be done here. + \li init() is called after fork() but while still connected to the terminal. init() should + do all necessary application setup. Here, all configuration or user errors should be + detected and properly diagnosed. + \li After init() returns, the application will detach from the terminal. Now run() is called + to enter the application main loop. + + Since there are times, where separating init() and run() into two separate functions is + difficult, instead of defining init() and run(), the member main() may be defined. This + member must call detach() as soon as initialization is completed to detach from the + foreground terminal. + + + + \ingroup process + */ + class Daemon : boost::noncopyable + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + /// Select standard stream to redirect + enum StdStream { + StdOut /** Standard output stream */ + , StdErr /** Standard error stream */ + , Both /** Both, standard output and error stream */ + }; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///\{ + + virtual ~Daemon(); + + ///\} + ///\name Parameters + ///\{ + + void daemonize(bool); ///< Configure whether to run in fore- or background + bool daemon(); ///< \c true, if running as daemon + + void consoleLog(std::string, StdStream which = Both); ///< Configure console log file + /**< May be called multiple times to set the log file + for stdout and stderr seperately. Any standard stream + not assigned to a log file will be redirected to + /dev/null. + + When running in the foreground, the log files will be + ignored. */ + + void pidFile(std::string, bool unique = true); ///< Configure pid file + + ///\} + ///\name Auxiliary helpers + ///\{ + + void detach(); ///< Detach into background now + /**< This is \e not the same as forking. The process will + already have forked into the background but until + detach() is called (either automatically after init() + returns or manually), the front end (foreground) + process will wait for the background process to ensure + successful startup. */ + + int argc(); ///< Access command line parameter count + char const ** argv(); ///< Access command line parameters + + void fail(int code=1); ///< Terminate startup with failure + + ///\} + + int start(int argc, char const ** argv); ///< Called from main() to launch daemon. + /**< Normally not called directly but from the + \ref SENF_DAEMON_MAIN macro. */ + + protected: + Daemon(); + +# ifdef DOXYGEN + protected: +# else + private: +# endif + + virtual void configure(); ///< Called before forking to configure the daemon class + virtual void main(); ///< Called after forking to execute the main application + /**< The default implementation will call init(), detach() + and then run(). It is preferred to override init() and + run() if possible. */ + virtual void init(); ///< Called to initialize the main application + /**< While init() is running, the application still is + connected to the controlling terminal. Error messages + will be shown to the user. + + This member is only called, if the default main() + implementation is not overridden. */ + virtual void run(); ///< Called to execute main application + /**< Called after detaching from the controlling + terminal. + + This member is only called, if the default main() + implementation is not overridden. */ + private: + + void fork(); + void pidfileCreate(); + + int argc_; + char const ** argv_; + + bool daemonize_; + int stdout_; + int stderr_; + std::string pidfile_; + bool unique_; + + bool detached_; + }; + + /** \brief Provide \c main() function + + This macro will provide a \c main() function to launch the daemon process defined in \a + klass. \a klass must be a class derived from senf::Daemon. + + \ingroup process + */ +# define SENF_DAEMON_MAIN(klass) \ + int main(int argc, char const ** argv) \ + { \ + klass instance; \ + return instance.start(argc, argv); \ + } + /// \addtogroup process /// @{ @@ -81,4 +247,6 @@ namespace senf { // c-file-style: "senf" // indent-tabs-mode: nil // ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// comment-column: 40 // End: