qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject svn commit: r533819 - in /incubator/qpid/branches/M2/cpp: README lib/broker/Daemon.cpp lib/broker/Daemon.h lib/broker/Makefile.am qpidc.spec.in src/qpidd.cpp tests/Makefile.am tests/broker tests/daemon_test
Date Mon, 30 Apr 2007 18:08:18 GMT
Author: aconway
Date: Mon Apr 30 11:08:17 2007
New Revision: 533819

URL: http://svn.apache.org/viewvc?view=rev&rev=533819
Log:
* README: added new dependency, libdaemon.
* qpidc.spec.in: libdaemon dependencies.
* broker/Daemon.h|cpp: Daemon and pid file management, wrapper for libdaemon.
* qpidd.cpp modifid flags
  -d [ --daemon ] - waits till deamon is listening before returning.
* qpidd.cpp: new flags
  -q [ --quit ]                     Stop the running daemon politely.
  -k [ --kill ]                     Kill the running daemon harshly.
  -c [ --check ]                    If daemon is running return 0.
  --wait SECONDS (=10)              Maximum wait for daemon response.
  --ppid                            Print daemon pid to stdout
* tests/dameon_test: Test daemon startup, shutdown.
* deleted tests/broker: obsolete script.

Added:
    incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp   (with props)
    incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h   (with props)
    incubator/qpid/branches/M2/cpp/tests/daemon_test   (with props)
Removed:
    incubator/qpid/branches/M2/cpp/tests/broker
Modified:
    incubator/qpid/branches/M2/cpp/README
    incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am
    incubator/qpid/branches/M2/cpp/qpidc.spec.in
    incubator/qpid/branches/M2/cpp/src/qpidd.cpp
    incubator/qpid/branches/M2/cpp/tests/Makefile.am

Modified: incubator/qpid/branches/M2/cpp/README
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/README?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/README (original)
+++ incubator/qpid/branches/M2/cpp/README Mon Apr 30 11:08:17 2007
@@ -33,7 +33,7 @@
  * apr     <http://apr.apache.org>          (1.2.7)
  * boost   <http://www.boost.org>           (1.33.1)
  * cppunit <http://cppunit.sourceforge.net> (1.11.4)
-
+ * libdaemon <http://www.stud.uni-hamburg.de/users/lennart/projects/libdaemon> (0.10)
 Using tools:
 
  * boost-jam  <http://boost.sourceforge.net/>          (3.1.13)

Added: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp (added)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp Mon Apr 30 11:08:17 2007
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "QpidError.h"
+#include "Daemon.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;
+
+string Daemon::nameFromArgv0(const char* argv0) {
+    return string(daemon_ident_from_argv0(const_cast<char*>(argv0)));
+}
+
+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();
+}
+
+Daemon::Daemon(const string& name_, int secs) : 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.    
+}
+
+Daemon::~Daemon() {
+    if (isChild())
+        daemon_pid_file_remove();
+}
+
+class Daemon::Retval {
+  public:
+    Retval();
+    ~Retval();
+    int send(int s);
+    int wait(int timeout);
+  private:
+    bool completed;
+};
+
+pid_t Daemon::fork() {
+    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);
+        }
+    }
+    else if (pid == 0) { // child.
+        // TODO aconway 2007-04-26: Should log failures.
+        if (daemon_pid_file_create())
+            failed();
+    }
+    return pid;
+}
+
+void Daemon::notify(int i) {
+    assert(retval);
+    if (retval->send(i)) 
+        throw Exception("Failed to notify parent: "+strError(errno));
+}
+
+void Daemon::ready() { notify(0); }
+
+// NB: Not -1, confused with failure of fork() on the parent side.
+void Daemon::failed() { notify(errno? errno:-2); }
+
+void  Daemon::quit() {
+    if (daemon_pid_file_kill_wait(SIGINT, timeout))
+        throw Exception("Failed to stop daemon: " + strError(errno));
+}
+
+void  Daemon::kill() {
+    if (daemon_pid_file_kill_wait(SIGKILL, timeout) < 0)
+        throw Exception("Failed to stop daemon: " + strError(errno));
+}
+
+pid_t Daemon::check() {
+    return daemon_pid_file_is_running();
+}
+
+Daemon::Retval::Retval() : completed(false) {
+    daemon_retval_init();
+}
+Daemon::Retval::~Retval() {
+    if (!completed) daemon_retval_done();
+}
+int Daemon::Retval::send(int s) {
+    return daemon_retval_send(s);
+}
+int Daemon::Retval::wait(int timeout) {
+    return daemon_retval_wait(timeout);
+}
+
+}} // namespace qpid::broker

Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h (added)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h Mon Apr 30 11:08:17 2007
@@ -0,0 +1,91 @@
+#ifndef _broker_Daemon_h
+#define _broker_Daemon_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+#include <boost/scoped_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Tools for forking and managing a daemon process.
+ * NB: Only one Daemon instance is allowed in a process.
+ */
+class Daemon
+{
+  public:
+
+    /** Extract the daemon's name from argv[0] */
+    static std::string nameFromArgv0(const char* argv0);
+    
+    /**
+     * 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(const std::string& name, 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();
+    
+    /** Child only, send failed signal so parent fork() will throw. */
+    void failed();
+    
+    /** Kill the daemon with SIGINT. */
+    void quit();
+    
+    /** Kill the daemon with SIGKILL. */
+    void kill();
+
+    /** Check daemon is running, throw exception if not */
+    pid_t check();
+
+    bool isParent() { return pid > 0; }
+
+    bool isChild() { return pid == 0; }
+    
+    std::string getName() const { return name; }
+
+    pid_t getPid() const {return pid; }
+
+  private:
+    class Retval;
+
+    void notify(int);
+    
+    static std::string name;
+    static std::string pidFile;
+    static const char* getPidFile();
+    boost::scoped_ptr<Retval> retval;
+    pid_t pid;
+    int timeout;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif  /*!_broker_Daemon_h*/

Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am (original)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am Mon Apr 30 11:08:17 2007
@@ -7,7 +7,11 @@
   $(APR_CXXFLAGS)
 
 lib_LTLIBRARIES = libqpidbroker.la
-libqpidbroker_la_LIBADD = ../common/libqpidcommon.la
+libqpidbroker_la_LIBADD =			\
+  ../common/libqpidcommon.la			\
+  -ldaemon					\
+  -lboost_filesystem
+
 libqpidbroker_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
 libqpidbroker_la_SOURCES =			\
   AccumulatedAck.cpp				\
@@ -27,6 +31,8 @@
   ConnectionToken.h				\
   Consumer.h					\
   Content.h					\
+  Daemon.cpp					\
+  Daemon.h					\
   DeletingTxOp.cpp				\
   DeletingTxOp.h				\
   Deliverable.h					\

Modified: incubator/qpid/branches/M2/cpp/qpidc.spec.in
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/qpidc.spec.in?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/qpidc.spec.in (original)
+++ incubator/qpid/branches/M2/cpp/qpidc.spec.in Mon Apr 30 11:08:17 2007
@@ -13,17 +13,19 @@
 Source0:        http://rhm.et.redhat.com/download/%{name}-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
-BuildRequires: libtool
+BuildRequires: apr-devel
 BuildRequires: boost-devel
 BuildRequires: cppunit-devel
 BuildRequires: doxygen
+BuildRequires: e2fsprogs-devel
 BuildRequires: graphviz
 BuildRequires: help2man
+BuildRequires: libdaemon-devel
+BuildRequires: libtool
 BuildRequires: pkgconfig
-BuildRequires: e2fsprogs-devel
-BuildRequires: apr-devel
 
 Requires: boost
+Requires: libdaemon
 
 Requires(post):/sbin/chkconfig
 Requires(preun):/sbin/chkconfig

Modified: incubator/qpid/branches/M2/cpp/src/qpidd.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/src/qpidd.cpp?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/src/qpidd.cpp (original)
+++ incubator/qpid/branches/M2/cpp/src/qpidd.cpp Mon Apr 30 11:08:17 2007
@@ -19,35 +19,58 @@
  *
  */
 #include <Broker.h>
-#include <signal.h>
 #include <iostream>
 #include <memory>
 #include <config.h>
-#include <unistd.h>
 #include <fstream>
+#include <signal.h>
+#include <Daemon.h>
+#include <boost/format.hpp>
 
+using boost::format;
 using namespace qpid;
 using namespace qpid::broker;
 using namespace qpid::sys;
 using namespace std;
 
+Broker::shared_ptr brokerPtr;
+
+void handle_signal(int /*signal*/){
+    std::cerr << "Shutting down..." << std::endl;
+    brokerPtr->shutdown();
+}
+
+
 /** Command line options */
 struct QpiddOptions : public Broker::Options
 {
     bool help;
     bool version;
     bool daemon;
+    bool quit;
+    bool kill;
+    bool check;
+    bool ppid;
+    int wait;
     string config;
     po::options_description desc;
     
     QpiddOptions() :
         help(false), version(false), daemon(false),
+        quit(false), kill(false), check(false), ppid(false), wait(10),
         config("/etc/qpidd.conf"),
         desc("Options")
     {
         using namespace po;
         desc.add_options()
-            ("daemon,d", optValue(daemon), "Run as a daemon");
+            ("daemon,d", optValue(daemon), "Run as a daemon.")
+            ("quit,q", optValue(quit), "Stop the running daemon politely.")
+            ("kill,k", optValue(kill), "Kill the running daemon harshly.")
+            ("check,c", optValue(check), "If daemon is running return 0.")
+            ("wait", optValue(wait, "SECONDS"),
+             "Maximum wait for daemon response.")
+            ("ppid", optValue(ppid), "Print daemon pid to stdout" );
+        po::options_description brokerOpts;
         Broker::Options::addTo(desc);
         desc.add_options()
             ("config", optValue(config, "FILE"), "Configuation file")
@@ -87,43 +110,80 @@
     config.usage(out); return out;
 }
 
-Broker::shared_ptr brokerPtr;
-
-void handle_signal(int /*signal*/){
-    if (brokerPtr) {
-        cerr << "Shutting down..." << endl;
-        brokerPtr->shutdown();
-    }
-}
-
 int main(int argc, char* argv[])
 {
     QpiddOptions config;
     try {
         config.parse(argc, argv);
+        string name=(format("%s.%d")
+                     % Daemon::nameFromArgv0(argv[0])
+                     % (config.port)).str();
+        // Spelled 'demon' to avoid clash with daemon.h function.
+        Daemon demon(name, config.wait);
+
+        // Options that just print information.
         if(config.help) {
             config.usage(cout);
+            return 0;
         }
-        else if (config.version) {
+        if (config.version) {
             cout << "qpidd (" << PACKAGE_NAME << ") version "
                  << PACKAGE_VERSION << endl;
+            return 0;
         }
-        else {
-            brokerPtr=Broker::create(config);
-            signal(SIGINT, handle_signal);
-            if (config.daemon) {
-                if (daemon(0, 0) < 0) // daemon(nochdir, noclose)
-                    throw QPID_ERROR(
-                        INTERNAL_ERROR,
-                        "Failed to detach as daemon: "+ strError(errno));
+
+        // Options that affect an already running daemon.
+        if (config.quit || config.kill || config.check) {
+            pid_t pid = demon.check();
+            if (config.ppid && pid > 0)
+                cout << pid << endl;
+            if (config.kill)
+                demon.kill();
+            else if (config.quit)
+                demon.quit();
+            if (config.check && pid <= 0)
+                return 1;
+            return 0;
+        }
+
+        // Starting the broker:
+        signal(SIGINT, handle_signal);
+        if (config.daemon) {
+            pid_t pid = demon.fork();
+            if (pid == 0) {  // Child
+                try {
+                    brokerPtr=Broker::create(config);
+                    demon.ready();   // Notify parent we're ready.
+                    brokerPtr->run();
+                } catch (const exception& e) {
+                    // TODO aconway 2007-04-26: Log this, cerr is lost.
+                    cerr << "Broker daemon failed: " << e.what() << endl;
+                    demon.failed(); // Notify parent we failed.
+                    return 1;
+                }
+            }
+            else if (pid > 0) { // Parent
+                if (config.ppid)
+                    cout << pid << endl;
+                return 0;
             }
-            brokerPtr->run();
+            else { // pid < 0
+                throw Exception("fork failed"+strError(errno));
+            }
+        } // Non-daemon broker.
+        else {
+            brokerPtr = Broker::create(config);
+            brokerPtr->run(); 
         }
         return 0;
     }
-    catch(const exception& e) {
+    catch(const po::error& e) {
+        // Command line parsing error.
         cerr << "Error: " << e.what() << endl
              << "Type 'qpidd --help' for usage." << endl;
+    }
+    catch(const exception& e) {
+        cerr << "Error: " << e.what() << endl;
     }
     return 1;
 }

Modified: incubator/qpid/branches/M2/cpp/tests/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/tests/Makefile.am?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/tests/Makefile.am (original)
+++ incubator/qpid/branches/M2/cpp/tests/Makefile.am Mon Apr 30 11:08:17 2007
@@ -71,10 +71,10 @@
 TESTS_ENVIRONMENT =			\
   VALGRIND=$(VALGRIND)			\
   abs_builddir='$(abs_builddir)'	\
-  PATH="$(abs_builddir)/../src$(PATH_SEPARATOR)$$PATH" \
+  PATH="$(abs_srcdir)$(PATH_SEPARATOR)$(abs_builddir)/../src$(PATH_SEPARATOR)$$PATH" \
   abs_srcdir='$(abs_srcdir)'
 
-TESTS = run-unit-tests run-python-tests
+TESTS = run-unit-tests run-python-tests daemon_test
 EXTRA_DIST += $(TESTS)
 
 CLEANFILES=qpidd.log

Added: incubator/qpid/branches/M2/cpp/tests/daemon_test
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/tests/daemon_test?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/tests/daemon_test (added)
+++ incubator/qpid/branches/M2/cpp/tests/daemon_test Mon Apr 30 11:08:17 2007
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Without arguments run all daemon tests, exit status is number of failures.
+# With arguments run just the test named by $1.
+#
+
+TEMP=`mktemp`
+trap 'rm -f $TEMP' 0
+
+fail() { echo FAIL: $0:$* 1>&2; exit 1; }
+
+# Start and stop daemon.
+PID=`qpidd --check --ppid` && fail $LINENO: qpidd already running $PID
+qpidd -d || $LINENO: qpidd -d failed
+qpidd --check || fail $LINENO: qpidd --check says qpidd didnt start
+client_test > $TEMP || fail $LINENO:  client_test: `cat $TEMP`
+qpidd -q || fail $LINENO: qpidd -q failed
+qpidd -d || fail $LINENO: restart after quit failed.
+qpidd -k || fail $LINENO: qpidd -k failed
+# Supress expected message re. cleanup of old PID file.
+PID=`qpidd --check --ppid 2>/dev/null` && fail $LINENO: $PID still running after
kill. 
+
+true

Propchange: incubator/qpid/branches/M2/cpp/tests/daemon_test
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message