Scheduler: Implement PollTimerSource
[senf.git] / Utils / Daemon / Daemon.cc
index 079b383..8cbf98f 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <limits.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <signal.h>
@@ -43,6 +44,7 @@
 #include "../Exception.hh"
 #include "../membind.hh"
 #include "../Backtrace.hh"
+#include "../signalnames.hh"
 
 // #define __USE_GNU
 #include <ucontext.h>
@@ -87,11 +89,29 @@ prefix_ int senf::Daemon::argc()
     return argc_;
 }
 
-prefix_ char ** senf::Daemon::argv() 
+prefix_ char const ** senf::Daemon::argv() 
 {
     return argv_;
 }
 
+namespace {
+
+    struct IsDaemonOpt {
+        bool operator()(std::string const & str) const {
+            return str == "--no-daemon"
+                || boost::starts_with(str, std::string("--pid-file="))
+                || boost::starts_with(str, std::string("--console-log="));
+        }
+    };
+}
+
+prefix_ void senf::Daemon::removeDaemonArgs()
+{
+    char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
+    *last = 0;
+    argc_ = last - argv_;
+}
+
 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
 {
     switch (which) {
@@ -112,8 +132,11 @@ prefix_ void senf::Daemon::openLog()
                   << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
         stdout_ = fd;
     }
-    if (stderrLog_ == stdoutLog_)
-        stderr_ = fd;
+    if (stderrLog_ == stdoutLog_) {
+        stderr_ = ::dup(fd);
+        if (stderr_ < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::dup()");
+    } 
     else if (! stderrLog_.empty()) {
         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
         if (fd < 0)
@@ -218,7 +241,7 @@ prefix_ void senf::Daemon::exit(unsigned code)
     throw DaemonExitException(code);
 }
 
-prefix_ int senf::Daemon::start(int argc, char ** argv)
+prefix_ int senf::Daemon::start(int argc, char const ** argv)
 {
     argc_ = argc;
     argv_ = argv;
@@ -287,6 +310,7 @@ senf::Daemon * senf::Daemon::instance_ (0);
 
 prefix_ void senf::Daemon::configure()
 {
+    // int i (not unsigned) since argc_ is int ...
     for (int i (1); i<argc_; ++i) {
         if (argv_[i] == std::string("--no-daemon"))
             daemonize(false);
@@ -344,6 +368,15 @@ prefix_ void senf::Daemon::fork()
     ::sigemptyset(&cldsig);
     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
+
+    if (! senf::scheduler::empty() )
+        std::cerr << 
+            "\n"
+            "*** WARNING ***\n"
+            "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
+            "The scheduler will be reinitialized by the fork() and lose all registrations.\n"
+            "*** WARNING ***\n"
+            "\n";
     
     LIBC_CALL_RV( pid, ::fork, () );
 
@@ -358,6 +391,8 @@ prefix_ void senf::Daemon::fork()
         LIBC_CALL( ::close, (cerrpipe[1]) );
         LIBC_CALL( ::setsid, () );
         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
+
+        senf::scheduler::restart();
         return;
     }
 
@@ -367,6 +402,8 @@ prefix_ void senf::Daemon::fork()
     LIBC_CALL( ::close, (coutpipe[1]) );
     LIBC_CALL( ::close, (cerrpipe[1]) );
 
+    senf::scheduler::restart();
+
     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
     watcher.run();
 
@@ -469,19 +506,9 @@ prefix_ bool senf::Daemon::pidfileCreate()
 namespace {
     void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
     {
-        static char const * const signames[] = {
-            "", 
-            "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", 
-            "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", 
-            "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", 
-            "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", 
-            "SIGPWR", "SIGSYS" };
-
         // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
-        std::cerr << "\n" << "Signal " << sig;
-        if (unsigned(sig) < sizeof(signames) / sizeof(signames[0]))
-            std::cerr << " (" << signames[unsigned(sig)] << ")";
-        std::cerr << " received\n";
+        std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
+                  << " received\n";
 
         if (sig == SIGSEGV)
             std::cerr << "Invalid memory access at " << info->si_addr << "\n";
@@ -523,6 +550,9 @@ prefix_ void senf::Daemon::installSighandlers()
 
     ::sigaction(SIGHUP,   &sa, NULL);
 
+    sa.sa_handler = SIG_IGN;
+    ::sigaction(SIGPIPE, &sa, NULL);
+
 #ifdef SENF_DEBUG
     sa.sa_sigaction = &fatalSignalsHandler;
     sa.sa_flags = SA_RESTART | SA_SIGINFO;
@@ -546,6 +576,8 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce
                                                    int stdout, int stderr)
     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
       stderr_(stderr), sigChld_(false),
+      cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
+      timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), 
       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) 
 {
@@ -559,8 +591,7 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce
 
 prefix_ void senf::detail::DaemonWatcher::run()
 {
-    Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
-    Scheduler::instance().process();
+    scheduler::process();
 }
 
 ////////////////////////////////////////
@@ -576,15 +607,13 @@ prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
     if (coutpipe_ == -1 && cerrpipe_ == -1) {
         if (sigChld_)
             childDied(); // does not return
-        if (::kill(childPid_, SIGUSR1) < 0)
-            if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
-        Scheduler::instance().timeout(
-            Scheduler::instance().eventTime() + ClockService::seconds(1),
-            senf::membind(&DaemonWatcher::childOk, this));
+        if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
+            SENF_THROW_SYSTEM_EXCEPTION("::kill()");
+        timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
     }
 }
 
-prefix_ void senf::detail::DaemonWatcher::sigChld()
+prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
 {
     sigChld_ = true;
     if (coutpipe_ == -1 && cerrpipe_ == -1)
@@ -599,45 +628,38 @@ prefix_ void senf::detail::DaemonWatcher::childDied()
         ::signal(WTERMSIG(status),SIG_DFL);
         ::kill(::getpid(), WTERMSIG(status));
         // should not be reached
-        ::_exit(1);
+        ::_exit(126);
     }
     if (WEXITSTATUS(status) == 0)
-        ::_exit(1);
+        ::_exit(127);
     ::_exit(WEXITSTATUS(status));
 }
 
 prefix_ void senf::detail::DaemonWatcher::childOk()
 {
-    Scheduler::instance().terminate();
+    scheduler::terminate();
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // senf::detail::DaemonWatcher::Forwarder
 
 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
-    : src_(src), cb_(cb)
-{
-    Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
-                              Scheduler::EV_READ);
-}
+    : src_(src), cb_(cb), 
+      readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
+                 src_, scheduler::FdEvent::EV_READ)
+{}
 
 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
 {
-    if (src_ != -1)
-        Scheduler::instance().remove(src_);
-    
-    for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
-        if (i->offset >= buffer_.size())
-            Scheduler::instance().remove(i->fd);
+    targets_.clear_and_destroy(DestroyDelete());
 }
 
 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
 {
-    Target target = { fd, 0 };
-    targets_.push_back(target);
+    targets_.push_back(*(new Target(*this, fd)));
 }
 
-prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
+prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
 {
     char buf[1024];
     int n (0);
@@ -645,17 +667,18 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId
     while (1) {
         n = ::read(src_,buf,1024);
         if (n<0) {
-            if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
-        } else 
+            if (errno != EINTR) 
+                SENF_THROW_SYSTEM_EXCEPTION("::read()");
+        } 
+        else 
             break;
     }
 
     if (n == 0) {
-        // Hangup
-        Scheduler::instance().remove(src_);
         if (buffer_.empty())
             cb_(); 
         src_ = -1;
+        readevent_.disable();
         return;
     }
 
@@ -664,20 +687,16 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId
 
     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
         if (i->offset >= buffer_.size())
-            Scheduler::instance().add( i->fd, 
-                                       boost::bind(&Forwarder::writeData, this, _1, i),
-                                       Scheduler::EV_WRITE );
+            i->writeevent.enable();
 
     buffer_.insert(buffer_.end(), buf, buf+n);
 }
 
-prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
-                                                               Targets::iterator target)
+prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
 {    
-    if (event != Scheduler::EV_WRITE) {
+    if (event != scheduler::FdEvent::EV_WRITE) {
         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
-        Scheduler::instance().remove(target->fd);
-        targets_.erase(target);
+        targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
         if (targets_.empty() && src_ == -1)
             cb_();
         return;
@@ -704,7 +723,7 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventI
         i->offset -= n;
 
     if (target->offset >= buffer_.size())
-        Scheduler::instance().remove(target->fd);
+        target->writeevent.disable();
     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
         cb_();
 }