diff options
Diffstat (limited to 'cpp/src/qpid/broker')
| -rw-r--r-- | cpp/src/qpid/broker/Daemon.cpp | 99 | ||||
| -rw-r--r-- | cpp/src/qpid/broker/Daemon.h | 50 |
2 files changed, 80 insertions, 69 deletions
diff --git a/cpp/src/qpid/broker/Daemon.cpp b/cpp/src/qpid/broker/Daemon.cpp index 3c5a642b60..2b64e7761b 100644 --- a/cpp/src/qpid/broker/Daemon.cpp +++ b/cpp/src/qpid/broker/Daemon.cpp @@ -16,50 +16,35 @@ * */ #include "Daemon.h" +#include "qpid/log/Statement.h" #include "qpid/QpidError.h" #include <libdaemon/daemon.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <signal.h> -#include <boost/filesystem/path.hpp> -#include <boost/filesystem/operations.hpp> namespace qpid { namespace broker { using namespace std; -string Daemon::pidFile; -string Daemon::name; +boost::function<std::string()> qpid::broker::Daemon::pidFileFn; -string Daemon::nameFromArgv0(const char* argv0) { - return string(daemon_ident_from_argv0(const_cast<char*>(argv0))); +std::string Daemon::defaultPidFile(const std::string& identifier) { + daemon_pid_file_ident=identifier.c_str(); + return daemon_pid_file_proc_default(); } -const char* Daemon::getPidFile() { - if (pidFile.empty()) { - const char* home=getenv("HOME"); - if (!home) - throw(Exception("$HOME is not set, cant create $HOME/.qpidd.")); - using namespace boost::filesystem; - path dir = path(home,native) / path(".qpidd", native); - create_directory(dir); - dir /= name; - pidFile = dir.string(); - } - return pidFile.c_str(); +const char* Daemon::realPidFileFn() { + static std::string str = pidFileFn(); + return str.c_str(); } -Daemon::Daemon(const string& name_, int secs) : pid(-1), timeout(secs) +Daemon::Daemon(boost::function<std::string()> fn, int secs) : pid(-1), timeout(secs) { - name = name_; - daemon_pid_file_ident = daemon_log_ident = name.c_str(); - if (getuid() != 0) { - // For normal users put pid file under $HOME/.qpid - daemon_pid_file_proc = getPidFile; - } - // For root use the libdaemon default: /var/run. + pidFileFn = fn; + daemon_pid_file_proc = &realPidFileFn; } Daemon::~Daemon() { @@ -77,44 +62,58 @@ class Daemon::Retval { bool completed; }; -pid_t Daemon::fork() { +pid_t Daemon::fork(Function parent, Function child) { retval.reset(new Retval()); pid = daemon_fork(); if (pid < 0) - throw Exception("Failed to fork daemon: "+strError(errno)); - else if (pid > 0) { - int ret = retval->wait(timeout); // parent, wait for child. - if (ret != 0) { - string err; - if (ret > 0) - err = strError(ret); - else if (ret == -1) - err= strError(errno); - else - err= "unknown error"; - throw Exception("Deamon startup failed: "+err); + throw Exception("Failed to fork daemon: "+strError(errno)); + else if (pid == 0) { + try { + child(*this); + } catch (const exception& e) { + QPID_LOG(debug, "Rethrowing: " << e.what()); + failed(); // Notify parent + throw; } } - else if (pid == 0) { // child. - // TODO aconway 2007-04-26: Should log failures. - if (daemon_pid_file_create()) - failed(); - } + else + parent(*this); return pid; } -void Daemon::notify(int i) { +int Daemon::wait() { // parent + assert(retval); + errno = 0; // Clear errno. + int ret = retval->wait(timeout); // wait for child. + if (ret == -1) { + if (errno) + throw Exception("Error waiting for daemon startup:" + +strError(errno)); + else + throw Exception("Error waiting for daemon startup, check logs."); + } + return ret; +} + +void Daemon::notify(int value) { // child assert(retval); - if (retval->send(i)) + if (retval->send(value)) throw Exception("Failed to notify parent: "+strError(errno)); } -void Daemon::ready() { notify(0); } +void Daemon::ready(int value) { // child + if (value==-1) + throw Exception("Invalid value in Dameon::notify"); + errno = 0; + if (daemon_pid_file_create() != 0) + throw Exception(string("Failed to create PID file ") + + daemon_pid_file_proc()+": "+strError(errno)); + notify(value); +} -// NB: Not -1, confused with failure of fork() on the parent side. -void Daemon::failed() { notify(errno? errno:-2); } +void Daemon::failed() { notify(-1); } -void Daemon::quit() { +void Daemon::quit() { if (daemon_pid_file_kill_wait(SIGINT, timeout)) throw Exception("Failed to stop daemon: " + strError(errno)); } diff --git a/cpp/src/qpid/broker/Daemon.h b/cpp/src/qpid/broker/Daemon.h index cf9bf13764..cf7ad37b3a 100644 --- a/cpp/src/qpid/broker/Daemon.h +++ b/cpp/src/qpid/broker/Daemon.h @@ -21,6 +21,7 @@ #include <string> #include <boost/scoped_ptr.hpp> +#include <boost/function.hpp> namespace qpid { namespace broker { @@ -32,24 +33,39 @@ namespace broker { class Daemon { public: - - /** Extract the daemon's name from argv[0] */ - static std::string nameFromArgv0(const char* argv0); + /** Utility function to create pid file name in a standard place + * (may require root acces) using identifier as the file name. + */ + static std::string defaultPidFile(const std::string& identifier); /** - * Creating a Daemon instance forks a daemon process. - *@param name used to create pid files etc. - *@param timeout in seconds for all operations that wait. + * Daemon control object. + *@param pidFileFn Function that will comupte a PID file name. + * Called when pid file is created in ready() + *@param timeout in seconds for any operations that wait. */ - Daemon(const std::string& name, int timeout); + Daemon(boost::function<std::string()> pidFileFn, int timeout); ~Daemon(); - - /** Fork the daemon, wait till it signals readiness */ - pid_t fork(); - /** Child only, send ready signal so parent fork() will return. */ - void ready(); + typedef boost::function<void(Daemon&)> Function; + + /** Fork the daemon. + *@param parent called in the parent process. + *@param child called in the child process. + */ + pid_t fork(Function parent, Function child); + + /** Parent only: wait for child to indicate it is ready. + * @return value child passed to ready() */ + int wait(); + + /** Child only. Notify the parent we are ready and write the + * PID file. + *@param value returned by parent call to wait(). -1 is reserved + * for signalling an error. + */ + void ready(int value); /** Child only, send failed signal so parent fork() will throw. */ void failed(); @@ -67,18 +83,16 @@ class Daemon bool isChild() { return pid == 0; } - std::string getName() const { return name; } - pid_t getPid() const {return pid; } private: class Retval; + static boost::function<std::string()> pidFileFn; + static const char* realPidFileFn(); void notify(int); - static std::string name; - static std::string pidFile; - static const char* getPidFile(); + static std::string identifier; boost::scoped_ptr<Retval> retval; pid_t pid; int timeout; @@ -86,6 +100,4 @@ class Daemon }} // namespace qpid::broker - - #endif /*!_broker_Daemon_h*/ |
