Utils: Add singleton alive test member
g0dil [Wed, 17 Sep 2008 07:49:08 +0000 (07:49 +0000)]
Scheduler: Fix FIFORunner exception safety
Scheduler: Implement new signal event API
Migrate SENF to use new signal API

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@906 270642c3-0616-0410-b53a-bc976706d245

26 files changed:
SConstruct
Scheduler/FIFORunner.cc
Scheduler/FIFORunner.hh
Scheduler/FdDispatcher.test.cc
Scheduler/FdManager.hh
Scheduler/FileDispatcher.test.cc
Scheduler/Scheduler.cc
Scheduler/Scheduler.cci
Scheduler/Scheduler.hh
Scheduler/Scheduler.test.cc
Scheduler/SignalDispatcher.hh [deleted file]
Scheduler/SignalEvent.cc [moved from Scheduler/SignalDispatcher.cc with 54% similarity]
Scheduler/SignalEvent.cci [moved from Scheduler/SignalDispatcher.cci with 56% similarity]
Scheduler/SignalEvent.hh [new file with mode: 0644]
Scheduler/SignalEvent.ih [new file with mode: 0644]
Scheduler/SignalEvent.test.cc [moved from Scheduler/SignalDispatcher.test.cc with 67% similarity]
Scheduler/TimerDispatcher.test.cc
Utils/Daemon/Daemon.cc
Utils/Daemon/Daemon.ih
Utils/Daemon/Daemon.test.cc
Utils/singleton.cti
Utils/singleton.hh
Utils/singleton.test.cc
senfscons/CompileCheck.py
senfscons/SENFSCons.py
senfscons/senfutil.py

index 0e0f4d7..3ae0d5e 100644 (file)
@@ -173,6 +173,21 @@ env.Append(
                     'config.hh', 'local_config.hh' ],
 )
 
+def parseLogOption(value):
+    stream, area, level = ( x.strip() for x in value.strip().split('|') )
+    if stream  : stream = ''.join('(%s)' % x for x in stream.split('::') )
+    else       : stream = '(_)'
+    if area : area = ''.join( '(%s)' % x for x in area.split('::') )
+    else    : area = '(_)'
+    return '(( %s,%s,%s ))' % (stream,area,level)
+
+def expandLogOption(target, source, env, for_signature):
+    return ' '.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )
+
+if env.subst('$LOGLEVELS'):
+    env.Append( expandLogOption=expandLogOption )
+    env.Append( CPPDEFINES = { 'SENF_LOG_CONF': '$expandLogOption' } )
+
 env.SetDefault(
        LIBSENF = "senf"
 )
index ffaf11e..7fbd9df 100644 (file)
@@ -30,6 +30,7 @@
 #include <signal.h>
 #include <time.h>
 #include "../Utils/Exception.hh"
+#include "../Utils/senfassert.hh"
 
 //#include "FIFORunner.mpp"
 #define prefix_
@@ -116,32 +117,45 @@ prefix_ void senf::scheduler::FIFORunner::run()
     // - We keep the next to-be-processed node in a class variable which is checked and updated
     //   whenever a node is removed.
     NullTask null;
-    tasks_.push_back(null);
-    TaskList::iterator end (TaskList::current(null));
-    next_ = tasks_.begin();
     struct itimerspec timer;
     timer.it_interval.tv_sec = watchdogMs_ / 1000;
     timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
     timer.it_value.tv_sec = timer.it_interval.tv_sec;
     timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
-    if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
-    while (next_ != end) {
-        TaskInfo & task (*next_);
-        if (task.runnable) {
-            task.runnable = false;
-            runningName_ = task.name;
-#       ifdef SENF_DEBUG
-            runningBacktrace_ = task.backtrace;
-#       endif
-            TaskList::iterator i (next_);
-            ++ next_;
-            tasks_.splice(tasks_.end(), tasks_, i);
-            watchdogCount_ = 1;
-            task.run();
+    tasks_.push_back(null);
+    TaskList::iterator end (TaskList::current(null));
+    next_ = tasks_.begin();
+    try {
+        if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
+        while (next_ != end) {
+            TaskInfo & task (*next_);
+            if (task.runnable) {
+                task.runnable = false;
+                runningName_ = task.name;
+#           ifdef SENF_DEBUG
+                runningBacktrace_ = task.backtrace;
+#           endif
+                TaskList::iterator i (next_);
+                ++ next_;
+                tasks_.splice(tasks_.end(), tasks_, i);
+                watchdogCount_ = 1;
+                task.run();
+            }
+            else
+                ++ next_;
         }
-        else
-            ++ next_;
+    }
+    catch (...) {
+        watchdogCount_ = 0;
+        timer.it_interval.tv_sec = 0;
+        timer.it_interval.tv_nsec = 0;
+        timer.it_value.tv_sec = 0;
+        timer.it_value.tv_nsec = 0;
+        timer_settime(watchdogId_, 0, &timer, 0);
+        tasks_.erase(end);
+        next_ = tasks_.end();
+        throw;
     }
     watchdogCount_ = 0;
     timer.it_interval.tv_sec = 0;
index 464d4f4..756f07f 100644 (file)
 #include <boost/utility.hpp>
 #include "../boost/intrusive/ilist.hpp"
 #include "../boost/intrusive/ilist_hook.hpp"
+#include "../Utils/singleton.hh"
 
 //#include "FIFORunner.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf { 
+
+    class Scheduler;
+
 namespace scheduler {
 
     /** \brief Task execution scheduler
@@ -48,7 +52,7 @@ namespace scheduler {
         is posted for the task.
       */
     class FIFORunner
-        : boost::noncopyable
+        : public singleton<FIFORunner>
     {
     public:
         struct TaskInfo;
@@ -56,8 +60,7 @@ namespace scheduler {
     private:
         struct TaskListTag;
         typedef boost::intrusive::ilist_base_hook<TaskListTag> TaskListBase;
-        typedef TaskListBase::value_traits<TaskInfo> TaskListType;
-        typedef boost::intrusive::ilist<TaskListType, false> TaskList;
+        typedef boost::intrusive::ilist<TaskListBase::value_traits<TaskInfo>, false> TaskList;
 
     public:
         ///////////////////////////////////////////////////////////////////////////
@@ -89,8 +92,8 @@ namespace scheduler {
         ///\name Structors and default members
         ///@{
 
-        FIFORunner();
-        ~FIFORunner();
+        using singleton<FIFORunner>::instance;
+        using singleton<FIFORunner>::alive;
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
@@ -112,6 +115,9 @@ namespace scheduler {
     protected:
 
     private:
+        FIFORunner();
+        ~FIFORunner();
+
         static void watchdog(int, siginfo_t *, void *);
 
         TaskList tasks_;
@@ -124,6 +130,9 @@ namespace scheduler {
 #   endif
         unsigned watchdogCount_;
         unsigned hangCount_;
+
+        friend class singleton<FIFORunner>;
+        friend class senf::Scheduler;
     };
 
 
index 853d862..6e20cc8 100644 (file)
@@ -162,10 +162,8 @@ namespace {
 
 BOOST_AUTO_UNIT_TEST(fdDispatcher)
 {
-    senf::scheduler::FdManager manager;
-    senf::scheduler::FIFORunner runner;
-    senf::scheduler::FdDispatcher dispatcher (manager, runner);
-    manager.timeout(1000);
+    senf::scheduler::FdDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance());
+    senf::scheduler::FdManager::instance().timeout(1000);
 
     int pid (start_server());
     BOOST_REQUIRE( pid );
@@ -188,8 +186,8 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher)
     BOOST_CHECK( dispatcher.add("testHandler", sock, boost::bind(&callback, sock, _1),
                                 senf::scheduler::FdDispatcher::EV_READ) );
     event = 0;
-    SENF_CHECK_NO_THROW( manager.processOnce() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_READ );
     BOOST_CHECK_EQUAL( size, 4 );
     buffer[size] = 0;
@@ -201,29 +199,29 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher)
                                 senf::scheduler::FdDispatcher::EV_WRITE) );
     event = 0;
     sleep(1);
-    SENF_CHECK_NO_THROW( manager.processOnce() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_WRITE );
 
     SENF_CHECK_NO_THROW( dispatcher.remove(sock, senf::scheduler::FdDispatcher::EV_WRITE) );
     event = 0;
     sleep(1);
-    SENF_CHECK_NO_THROW( manager.processOnce() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_HUP | senf::scheduler::FdDispatcher::EV_READ );
     BOOST_CHECK_EQUAL( size, 2 );
     buffer[size]=0;
     BOOST_CHECK_EQUAL( buffer, "OK" );
 
     BOOST_CHECK_EQUAL( calls, 3 );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_EQUAL( calls, 3 );
     
     // Ensure, removing an already closed file-descriptor doesn't wreak havoc
     close(sock);
     SENF_CHECK_NO_THROW( dispatcher.remove(sock) );
 
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_EQUAL( calls, 3 );
 
 
index 4d7b05e..4845233 100644 (file)
 // Custom includes
 #include "Poller.hh"
 #include "ClockService.hh"
+#include "../Utils/singleton.hh"
 
 //#include "FdManager.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
+
+    class Scheduler;
+
 namespace scheduler {
 
     /** \brief Manage file descriptor event processing
@@ -53,6 +57,7 @@ namespace scheduler {
         \implementation
       */
     class FdManager
+        : public singleton<FdManager>
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
@@ -73,7 +78,8 @@ namespace scheduler {
         ///\name Structors and default members
         ///@{
 
-        FdManager();
+        using singleton<FdManager>::instance;
+        using singleton<FdManager>::alive;
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
@@ -106,8 +112,13 @@ namespace scheduler {
     protected:
 
     private:
+        FdManager();
+
         Poller<Event> poller_;
         senf::ClockService::clock_type eventTime_;
+
+        friend class singleton<FdManager>;
+        friend class senf::Scheduler;
     };
 
 }}
index f923616..b3c2bcd 100644 (file)
@@ -56,9 +56,7 @@ namespace {
 
 BOOST_AUTO_UNIT_TEST(fileDispatcher)
 {
-    senf::scheduler::FdManager manager;
-    senf::scheduler::FIFORunner runner;
-    senf::scheduler::FileDispatcher dispatcher (manager, runner);
+    senf::scheduler::FileDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance());
     dispatcher.timeout(500);
 
     // It's not necessary for the cb to be a real file .. it can be anything. The only thing is,
@@ -68,9 +66,9 @@ BOOST_AUTO_UNIT_TEST(fileDispatcher)
     senf::ClockService::clock_type t (senf::ClockService::now());
     SENF_CHECK_NO_THROW( dispatcher.add("testHandler", fd, &handler, 
                                         senf::scheduler::FileDispatcher::EV_READ) );
-    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
     SENF_CHECK_NO_THROW( dispatcher.prepareRun() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     
     BOOST_CHECK( called );
     BOOST_CHECK_PREDICATE( is_close, (t)(senf::ClockService::now()) );
@@ -80,9 +78,9 @@ BOOST_AUTO_UNIT_TEST(fileDispatcher)
 
     called = false;
     t = senf::ClockService::now();
-    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
     SENF_CHECK_NO_THROW( dispatcher.prepareRun() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
 
     BOOST_CHECK( ! called );
     BOOST_CHECK_PREDICATE( 
index 02364a4..1bfd963 100644 (file)
@@ -35,6 +35,7 @@
 //#include "Scheduler.ih"
 
 // Custom includes
+#include "SignalEvent.hh"
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
@@ -45,16 +46,40 @@ prefix_ void senf::Scheduler::process()
     while(! terminate_ && ! (fdDispatcher_.empty() &&
                              timerDispatcher_.empty() &&
                              fileDispatcher_.empty())) {
-        signalDispatcher_.unblockSignals();
+        scheduler::detail::SignalDispatcher::instance().unblockSignals();
         timerDispatcher_.unblockSignals();
-        manager_.processOnce();
+        scheduler::FdManager::instance().processOnce();
         timerDispatcher_.blockSignals();
-        signalDispatcher_.blockSignals();
+        scheduler::detail::SignalDispatcher::instance().blockSignals();
         fileDispatcher_.prepareRun();
-        runner_.run();
+        scheduler::FIFORunner::instance().run();
     }
 }
 
+prefix_ void senf::Scheduler::restart()
+{
+    scheduler::FdManager* fdm (&scheduler::FdManager::instance());
+    scheduler::FIFORunner* ffr (&scheduler::FIFORunner::instance());
+    scheduler::FdDispatcher* fdd (&fdDispatcher_);
+    scheduler::TimerDispatcher* td (&timerDispatcher_);
+    scheduler::detail::SignalDispatcher* sd (&scheduler::detail::SignalDispatcher::instance());
+    scheduler::FileDispatcher* fld (&fileDispatcher_);
+    
+    fld->~FileDispatcher();
+    sd->~SignalDispatcher();
+    td->~TimerDispatcher();
+    fdd->~FdDispatcher();
+    ffr->~FIFORunner();
+    fdm->~FdManager();
+    
+    new (fdm) scheduler::FdManager();
+    new (ffr) scheduler::FIFORunner();
+    new (fdd) scheduler::FdDispatcher(*fdm, *ffr);
+    new (td) scheduler::TimerDispatcher(*fdm, *ffr);
+    new (sd) scheduler::detail::SignalDispatcher();
+    new (fld) scheduler::FileDispatcher(*fdm, *ffr);
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::SchedulerLogTimeSource
 
index 5379b6f..94cd693 100644 (file)
@@ -113,16 +113,6 @@ prefix_ void senf::Scheduler::timeoutAdjust(ClockService::clock_type v)
               ("timeoutAdjust() is deprecated and a no-op. It will be removed") );
 }
 
-prefix_ void senf::Scheduler::registerSignal(unsigned signal, SignalCallback const & cb)
-{
-    signalDispatcher_.add(signal, cb);
-}
-
-prefix_ void senf::Scheduler::unregisterSignal(unsigned signal)
-{
-    signalDispatcher_.remove(signal);
-}
-
 prefix_ void senf::Scheduler::terminate()
 {
     terminate_ = true;
@@ -131,32 +121,31 @@ prefix_ void senf::Scheduler::terminate()
 prefix_ senf::ClockService::clock_type senf::Scheduler::eventTime()
     const
 {
-    return manager_.eventTime();
+    return scheduler::FdManager::instance().eventTime();
 }
 
 prefix_ void senf::Scheduler::taskTimeout(unsigned ms)
 {
-    runner_.taskTimeout(ms);
+    scheduler::FIFORunner::instance().taskTimeout(ms);
 }
 
 prefix_ unsigned senf::Scheduler::taskTimeout()
     const
 {
-    return runner_.taskTimeout();
+    return scheduler::FIFORunner::instance().taskTimeout();
 }
 
 prefix_ unsigned senf::Scheduler::hangCount()
     const
 {
-    return runner_.hangCount();
+    return scheduler::FIFORunner::instance().hangCount();
 }
 
 prefix_ senf::Scheduler::Scheduler()
     : terminate_ (false), 
-      fdDispatcher_ (manager_, runner_),
-      timerDispatcher_ (manager_, runner_),
-      signalDispatcher_ (manager_, runner_),
-      fileDispatcher_ (manager_, runner_)
+      fdDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()),
+      timerDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()),
+      fileDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance())
 {}
 
 ///////////////////////////////cci.e///////////////////////////////////////
index 4a7a74d..7c4dbcb 100644 (file)
@@ -31,7 +31,7 @@
 #include "../Utils/Logger/SenfLog.hh"
 #include "FdDispatcher.hh"
 #include "TimerDispatcher.hh"
-#include "SignalDispatcher.hh"
+#include "SignalEvent.hh"
 #include "FileDispatcher.hh"
 #include "../Utils/Logger/SenfLog.hh"
 
@@ -282,20 +282,6 @@ namespace senf {
 
         ///\}
 
-        ///\name Signal handlers
-        ///\{
-        
-        void registerSignal(unsigned signal, SignalCallback const & cb);
-                                        ///< Add signal handler
-                                        /**< \param[in] signal signal number to register handler for
-                                             \param[in] cb callback to call whenever \a signal is
-                                                 delivered. */
-
-        void unregisterSignal(unsigned signal);
-                                        ///< Remove signal handler for \a signal
-
-        ///\}
-
         void process();                 ///< Event handler main loop
                                         /**< This member must be called at some time to enter the
                                              event handler main loop. Only while this function is
@@ -318,6 +304,8 @@ namespace senf {
         unsigned taskTimeout() const;
         unsigned hangCount() const;
 
+        void restart();
+
     protected:
 
     private:
@@ -329,12 +317,9 @@ namespace senf {
         void do_remove(int fd, int eventMask);
 
         bool terminate_;
-        scheduler::FdManager manager_;
-        scheduler::FIFORunner runner_;
 
         scheduler::FdDispatcher fdDispatcher_;
         scheduler::TimerDispatcher timerDispatcher_;
-        scheduler::SignalDispatcher signalDispatcher_;
         scheduler::FileDispatcher fileDispatcher_;
     };
 
index b45b1a3..3bd241d 100644 (file)
@@ -265,6 +265,7 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
     BOOST_CHECK( timeoutCalled );
     BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE );
 
+    BOOST_WARN_MESSAGE( false, "A 'Scheduler task hanging' error is expected to be signaled here." );
     BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(ClockService::now(), &blockingHandler) );
     BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
     BOOST_CHECK_EQUAL( Scheduler::instance().hangCount(), 1u );
@@ -291,15 +292,18 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
 
     unsigned tid (Scheduler::instance().timeout(
                       ClockService::now()+ClockService::milliseconds(400),&timeout));
-    BOOST_CHECK_NO_THROW( Scheduler::instance().registerSignal(SIGUSR1, &sigusr) );
-    t = ClockService::now();
-    ::kill(::getpid(), SIGUSR1);
-    delay(100);
+    {
+        senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr);
+
+        t = ClockService::now();
+        ::kill(::getpid(), SIGUSR1);
+        delay(100);
+        BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); 
+        BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) );
+        BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) );
+    } 
     BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); 
-    BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) );
-    BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) );
-    Scheduler::instance().cancelTimeout(tid);
-    BOOST_CHECK_NO_THROW( Scheduler::instance().unregisterSignal(SIGUSR1) );
+    BOOST_CHECK_NO_THROW( Scheduler::instance().cancelTimeout(tid) );
 
     ///////////////////////////////////////////////////////////////////////////
 
diff --git a/Scheduler/SignalDispatcher.hh b/Scheduler/SignalDispatcher.hh
deleted file mode 100644 (file)
index 2c2b7ae..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-// $Id$
-//
-// Copyright (C) 2008 
-// Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Stefan Bund <g0dil@berlios.de>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-/** \file
-    \brief SignalDispatcher public header */
-
-#ifndef HH_SignalDispatcher_
-#define HH_SignalDispatcher_ 1
-
-// Custom includes
-#include <signal.h>
-#include <map>
-#include "FdManager.hh"
-#include "FIFORunner.hh"
-
-//#include "SignalDispatcher.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-namespace scheduler {
-
-    /** \brief Scheduler dispatcher managing UNIX signals
-
-        This dispatcher supports registering UNIX signals with the Scheduler.
-
-        \implementation SignalDispatcher provides a single signal handler which all registered
-            signals are assigned to. When a signal is received, data is written to a pipe which has
-            been added to the FdManager and this signals the event.
-
-        \todo Add signal block/unblock management to the FdManager to reduce the number of
-            setprocmask() calls
-      */
-    class SignalDispatcher
-        : public FdManager::Event
-    {
-    public:
-        ///////////////////////////////////////////////////////////////////////////
-        // Types
-
-        typedef boost::function<void (siginfo_t const &)> Callback;
-
-        ///////////////////////////////////////////////////////////////////////////
-        ///\name Structors and default members
-        ///@{
-
-        SignalDispatcher(FdManager & manager, FIFORunner & runner);
-        ~SignalDispatcher();
-
-        ///@}
-        ///////////////////////////////////////////////////////////////////////////
-
-        void add(int signal, Callback const & cb); ///< Add signal event
-                                        /**< \param[in] signal signal number
-                                             \param[in] cb Callback */
-
-        void remove(int signal); ///< Unregister signal event
-
-        void unblockSignals();          ///< Unblock registered signals
-                                        /**< Must be called before waiting for an event */
-        void blockSignals();            ///< Block registered signals
-                                        /**< Must be called directly after FdManager returns */
-
-        bool empty() const;             ///< \c true, if no signal is registered.
-
-    protected:
-
-    private:
-        ///< Internal: UNIX signal event
-        struct SignalEvent
-            : public FIFORunner::TaskInfo
-        {
-            SignalEvent(int signal, Callback cb_);
-            virtual void run();
-
-            siginfo_t siginfo;
-            Callback cb;
-        };
-
-        virtual void signal(int events);
-        static void sigHandler(int signal, ::siginfo_t * siginfo, void *);
-
-        FdManager & manager_;
-        FIFORunner & runner_;
-
-        typedef std::map<int, SignalEvent> HandlerMap;
-        HandlerMap handlers_;
-
-        int sigPipe_[2];
-
-        bool blocked_;
-        sigset_t sigSet_;
-
-        static SignalDispatcher * instance_;
-    };
-
-
-}}
-
-///////////////////////////////hh.e////////////////////////////////////////
-#include "SignalDispatcher.cci"
-//#include "SignalDispatcher.ct"
-//#include "SignalDispatcher.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// comment-column: 40
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// End:
similarity index 54%
rename from Scheduler/SignalDispatcher.cc
rename to Scheduler/SignalEvent.cc
index 69d72bc..f083852 100644 (file)
 /** \file
     \brief SignalDispatcher non-inline non-template implementation */
 
-#include "SignalDispatcher.hh"
-//#include "SignalDispatcher.ih"
+#include "SignalEvent.hh"
+#include "SignalEvent.ih"
 
 // Custom includes
 #include "../Utils/senfassert.hh"
+#include "../Utils/signalnames.hh"
 
-//#include "SignalDispatcher.mpp"
+//#include "SignalEvent.mpp"
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-senf::scheduler::SignalDispatcher * senf::scheduler::SignalDispatcher::instance_ = 0;
-
-prefix_ senf::scheduler::SignalDispatcher::SignalDispatcher(FdManager & manager,
-                                                            FIFORunner & runner)
-    : manager_ (manager), runner_ (runner), blocked_ (true)
+prefix_ senf::scheduler::detail::SignalDispatcher::SignalDispatcher()
+    : blocked_ (true)
 {
-    SENF_ASSERT( !instance_ );
     if (pipe(sigPipe_) <0)
         SENF_THROW_SYSTEM_EXCEPTION("pipe()");
     sigemptyset(&sigSet_);
-    instance_ = this;
-    manager_.set(sigPipe_[0], FdManager::EV_READ, this);
+    FdManager::instance().set(sigPipe_[0], FdManager::EV_READ, this);
 }
 
-prefix_ senf::scheduler::SignalDispatcher::~SignalDispatcher()
+prefix_ senf::scheduler::detail::SignalDispatcher::~SignalDispatcher()
 {
-    for (HandlerMap::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
-        ::signal(i->first, SIG_DFL);
-        runner_.dequeue(&i->second);
+    for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
+        ::signal(i->signal_, SIG_DFL);
+        FIFORunner::instance().dequeue(&(*i));
     }
     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
-    manager_.remove(sigPipe_[0]);
+    FdManager::instance().remove(sigPipe_[0]);
     close(sigPipe_[0]);
     close(sigPipe_[1]);
-    instance_ = 0;
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::add(int signal, Callback const & cb)
+prefix_ void senf::scheduler::detail::SignalDispatcher::add(SignalEvent & event)
 {
-    HandlerMap::iterator i (handlers_.find(signal));
-    if (i != handlers_.end()) {
-        i->second.cb = cb;
-        return;
-    }
+    SignalSet::iterator i (handlers_.find(event));
+    if (i != handlers_.end())
+        throw DuplicateSignalRegistrationException() 
+            << " for signal " << signalName(event.signal_) << " (" << event.signal_ << ")";
 
-    i = handlers_.insert(std::make_pair(signal, SignalEvent(signal, cb))).first;
-    sigaddset(&sigSet_, signal);
-    runner_.enqueue(&i->second);
+    handlers_.insert(event);
+    sigaddset(&sigSet_, event.signal_);
+    FIFORunner::instance().enqueue(&event);
 
     sigset_t sig;
     sigemptyset(&sig);
-    sigaddset(&sig, signal);
+    sigaddset(&sig, event.signal_);
     sigprocmask(blocked_ ? SIG_BLOCK : SIG_UNBLOCK, &sig, 0);
 
     // Need to re-register all handlers to update sa_mask
-    for (HandlerMap::iterator j (handlers_.begin()); i != handlers_.end(); ++i) {
-        struct sigaction act;
-        act.sa_sigaction = &sigHandler;
-        act.sa_mask = sigSet_;
-        act.sa_flags = SA_SIGINFO | SA_RESTART;
-        if (j->first == SIGCLD)
+    struct sigaction act;
+    act.sa_sigaction = &sigHandler;
+    act.sa_mask = sigSet_;
+    act.sa_flags = SA_SIGINFO | SA_RESTART;
+    for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
+        if (i->signal_ == SIGCLD)
             act.sa_flags |= SA_NOCLDSTOP;
-        if (sigaction(j->first, &act, 0) < 0)
+        else
+            act.sa_flags &= ~SA_NOCLDSTOP;
+        if (sigaction(i->signal_, &act, 0) < 0)
             SENF_THROW_SYSTEM_EXCEPTION("sigaction()");
     }
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::remove(int signal)
+prefix_ void senf::scheduler::detail::SignalDispatcher::remove(SignalEvent & event)
 {
-    ::signal(signal, SIG_DFL);
+    ::signal(event.signal_, SIG_DFL);
+    FIFORunner::instance().dequeue(&event);
+    handlers_.erase(event);
     sigset_t sig;
     sigemptyset(&sig);
-    sigaddset(&sig, signal);
+    sigaddset(&sig, event.signal_);
     sigprocmask(SIG_UNBLOCK, &sig, 0);
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::signal(int events)
+prefix_ void senf::scheduler::detail::SignalDispatcher::signal(int events)
 {
     siginfo_t info;
     if (read(sigPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
         return;
-    HandlerMap::iterator i (handlers_.find(info.si_signo));
+    SignalSet::iterator i (handlers_.find(info.si_signo, FindNumericSignal()));
     if (i == handlers_.end())
         return;
-    i->second.siginfo = info;
-    i->second.runnable = true;
+    i->siginfo_ = info;
+    i->runnable = true;
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::sigHandler(int signal, ::siginfo_t * siginfo,
+prefix_ void senf::scheduler::detail::SignalDispatcher::sigHandler(int signal, ::siginfo_t * siginfo,
                                                            void *)
 {
-    SENF_ASSERT( instance_ );
+    SENF_ASSERT( alive() );
     // The manpage says, si_signo is unused in linux so we set it here
     siginfo->si_signo = signal; 
     // We can't do much on error anyway so we ignore errors here
-    write(instance_->sigPipe_[1], siginfo, sizeof(*siginfo));
+    write(instance().sigPipe_[1], siginfo, sizeof(*siginfo));
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
-//#include "SignalDispatcher.mpp"
+//#include "SignalEvent.mpp"
 
 \f
 // Local Variables:
similarity index 56%
rename from Scheduler/SignalDispatcher.cci
rename to Scheduler/SignalEvent.cci
index 84fe9ab..3a0407e 100644 (file)
 /** \file
     \brief SignalDispatcher inline non-template implementation */
 
-//#include "SignalDispatcher.ih"
+#include "SignalEvent.ih"
 
 // Custom includes
 #include <unistd.h>
 #include "../Utils/signalnames.hh"
+#include "../Utils/senfassert.hh"
 
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
 
-prefix_ void senf::scheduler::SignalDispatcher::blockSignals()
+prefix_ void senf::scheduler::detail::SignalDispatcher::blockSignals()
 {
     if (blocked_) return;
     sigprocmask(SIG_BLOCK, &sigSet_, 0);
     blocked_ = true;
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::unblockSignals()
+prefix_ void senf::scheduler::detail::SignalDispatcher::unblockSignals()
 {
     if (!blocked_) return;
     sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
     blocked_ = false;
 }
 
-prefix_ bool senf::scheduler::SignalDispatcher::empty()
+prefix_ bool senf::scheduler::detail::SignalDispatcher::empty()
     const
 {
     return handlers_.empty();
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::scheduler::SignalDispatcher::SignalEvent
+// senf::scheduler::SignalEvent
 
-prefix_ senf::scheduler::SignalDispatcher::SignalEvent::SignalEvent(int signal, Callback cb_)
-    : cb (cb_)
+prefix_ senf::scheduler::SignalEvent::SignalEvent(int signal, Callback cb,
+                                                  bool initiallyEnabled)
+    : signal_ (signal), enabled_ (initiallyEnabled), cb_ (cb)
 {
     name = signalName(signal);
+    if (enabled_)
+        senf::scheduler::detail::SignalDispatcher::instance().add(*this);
 }
 
-prefix_ void senf::scheduler::SignalDispatcher::SignalEvent::run()
+prefix_ senf::scheduler::SignalEvent::~SignalEvent()
 {
-    cb(siginfo);
+    if (senf::scheduler::detail::SignalDispatcher::alive())
+        senf::scheduler::detail::SignalDispatcher::instance().remove(*this);
+}
+
+prefix_ void senf::scheduler::SignalEvent::disable()
+{
+    if (enabled_) {
+        senf::scheduler::detail::SignalDispatcher::instance().remove(*this);
+        enabled_ = false;
+    }
+}
+
+prefix_ void senf::scheduler::SignalEvent::enable()
+{
+    if (! enabled_) {
+        senf::scheduler::detail::SignalDispatcher::instance().add(*this);
+        enabled_ = true;
+    }
+}
+
+prefix_ bool senf::scheduler::SignalEvent::enabled()
+    const
+{
+    return enabled_;
+}
+
+prefix_ void senf::scheduler::SignalEvent::action(Callback cb)
+{
+    cb_ = cb;
+}
+
+prefix_ void senf::scheduler::SignalEvent::run()
+{
+    cb_(siginfo_);
 }
 
 ///////////////////////////////cci.e///////////////////////////////////////
diff --git a/Scheduler/SignalEvent.hh b/Scheduler/SignalEvent.hh
new file mode 100644 (file)
index 0000000..a21c460
--- /dev/null
@@ -0,0 +1,129 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher public header */
+
+#ifndef HH_SignalDispatcher_
+#define HH_SignalDispatcher_ 1
+
+// Custom includes
+#include <signal.h>
+#include <boost/function.hpp>
+#include "FIFORunner.hh"
+#include "../boost/intrusive/iset_hook.hpp"
+
+//#include "SignalEvent.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+    class Scheduler;
+
+namespace scheduler {
+
+    namespace detail {
+        struct SignalSetTag;
+        typedef boost::intrusive::iset_base_hook<SignalSetTag> SignalSetBase;
+        struct SignalSetCompare;
+        struct FindNumericSignal;
+        struct SignalDispatcher;
+    }
+
+    /** \brief UNIX signal event
+
+        The SignalEvent class registers a callback for UNIX signals. The callback will be called \e
+        synchronously (not from within the UNIX signal handler) by the scheduler.
+
+        The SignalEvent class is an implementation of the RAII idiom: The event will be
+        automatically unregistered in the SignalEvent destructor. The SignalEvent instance should be
+        created within the same scope or on a scope below where the callback is defined (e.g. if the
+        callback is a member function it should be defined as a class member).
+     */
+    class SignalEvent
+        : public FIFORunner::TaskInfo,
+          public detail::SignalSetBase 
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void (siginfo_t const &)> Callback;
+                                        ///< Callback type
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        SignalEvent(int signal, Callback cb, bool initiallyEnabled=true);
+                                        ///< Register a signal event
+                                        /**< Registers \a cb as callback for the UNIX signal \a
+                                             signal. If \a initiallyEnabled is set \c false, the
+                                             callback will not be enabled automatically. Use
+                                             enable() to do so.
+                                             \param[in] signal UNIX signal to register callback for
+                                             \param[in] cb Callback to call
+                                             \param[in] initiallyEnabled if set \c false, do not
+                                                 enable callback automatically. */
+        ~SignalEvent();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        void disable();                 ///< Enable signal event registration
+        void enable();                  ///< Disable the signal event registration
+        bool enabled() const;           ///< \c true, if event enabled, \c false otherwise
+        void action(Callback cb);       ///< Change signal event callback
+
+    private:
+        virtual void run();
+        
+        int signal_;
+        bool enabled_;
+        Callback cb_;
+        siginfo_t siginfo_;
+
+        friend class detail::SignalSetCompare;
+        friend class detail::FindNumericSignal;
+        friend class detail::SignalDispatcher;
+        friend class senf::Scheduler;
+    };
+
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "SignalEvent.cci"
+//#include "SignalEvent.ct"
+//#include "SignalEvent.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/SignalEvent.ih b/Scheduler/SignalEvent.ih
new file mode 100644 (file)
index 0000000..7e96134
--- /dev/null
@@ -0,0 +1,114 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher internal header */
+
+#ifndef IH_SignalDispatcher_
+#define IH_SignalDispatcher_ 1
+
+// Custom includes
+#include "FdManager.hh"
+#include "../boost/intrusive/iset.hpp"
+#include "../Utils/Exception.hh"
+#include "../Utils/singleton.hh"
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+    
+    class Scheduler;
+
+namespace scheduler {
+namespace detail {
+
+    struct SignalSetCompare {
+        bool operator()(SignalEvent const & a, SignalEvent const & b) const
+            { return a.signal_ < b.signal_; }
+    };
+
+    struct FindNumericSignal {
+        bool operator()(SignalEvent const & a, int b) const
+            { return a.signal_ < b; } 
+        bool operator()(int a, SignalEvent const & b) const
+            { return a < b.signal_; }
+    };
+
+    class SignalDispatcher
+        : public FdManager::Event,
+          public singleton<SignalDispatcher>
+    {
+        typedef boost::intrusive::iset< SignalSetBase::value_traits<SignalEvent>,
+                                        SignalSetCompare,
+                                        false > SignalSet;
+    public:
+        using singleton<SignalDispatcher>::instance;
+        using singleton<SignalDispatcher>::alive;
+
+        void add(SignalEvent & event);
+        void remove(SignalEvent & event);
+
+        void unblockSignals();
+        void blockSignals();
+
+        bool empty() const;
+
+        struct DuplicateSignalRegistrationException : public Exception
+        { DuplicateSignalRegistrationException() 
+              : Exception("duplicate signal registration") {} };
+
+    protected:
+
+    private:
+        SignalDispatcher();
+        ~SignalDispatcher();
+
+        virtual void signal(int events);
+        static void sigHandler(int signal, ::siginfo_t * siginfo, void *);
+
+        SignalSet handlers_;
+
+        int sigPipe_[2];
+
+        bool blocked_;
+        sigset_t sigSet_;
+
+        friend class senf::scheduler::SignalEvent;
+        friend class singleton<SignalDispatcher>;
+        friend class senf::Scheduler;
+    };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
similarity index 67%
rename from Scheduler/SignalDispatcher.test.cc
rename to Scheduler/SignalEvent.test.cc
index 7531aae..d579acb 100644 (file)
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 /** \file
-    \brief SignalDispatcher.test unit tests */
+    \brief SignalEvent.test unit tests */
 
-//#include "SignalDispatcher.test.hh"
-//#include "SignalDispatcher.test.ih"
+//#include "SignalEvent.test.hh"
+//#include "SignalEvent.test.ih"
 
 // Custom includes
-#include "SignalDispatcher.hh"
+#include "SignalEvent.hh"
 
 #include "../Utils/auto_unit_test.hh"
 #include <boost/test/test_tools.hpp>
@@ -45,32 +45,25 @@ namespace {
 
 }
 
-#if 0
-// We can't test this when testing the Scheduler since the Scheduler instance
-// already uses the only SignalDispatcher instance allowed ...
-
 BOOST_AUTO_UNIT_TEST(signalDispatcher)
 {
-    senf::scheduler::FdManager manager;
-    senf::scheduler::FIFORunner runner;
-    senf::scheduler::SignalDispatcher dispatcher (manager, runner);
-    manager.timeout(1000);
+    senf::scheduler::FdManager::instance().timeout(1000);
+    senf::scheduler::SignalEvent sig (SIGUSR1, &handler);
 
-    SENF_CHECK_NO_THROW( dispatcher.add(SIGUSR1, &handler) );
+    SENF_CHECK_NO_THROW( sig.disable() );
+    SENF_CHECK_NO_THROW( sig.enable() );
+    SENF_CHECK_NO_THROW( sig.action(&handler) );
+    BOOST_CHECK( sig.enabled() );
     BOOST_CHECK( ! called );
     ::kill(::getpid(), SIGUSR1);
     sleep(1);
-    SENF_CHECK_NO_THROW( dispatcher.unblockSignals() );
-    SENF_CHECK_NO_THROW( manager.processOnce() );
-    SENF_CHECK_NO_THROW( dispatcher.blockSignals() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::detail::SignalDispatcher::instance().unblockSignals() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::detail::SignalDispatcher::instance().blockSignals() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK( called );
-
-    SENF_CHECK_NO_THROW( dispatcher.remove(SIGUSR1) );
 }
 
-#endif
-
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index 9f0599c..2795a8a 100644 (file)
@@ -52,19 +52,17 @@ namespace {
 
 BOOST_AUTO_UNIT_TEST(timerDispatcher)
 {
-    senf::scheduler::FdManager manager;
-    senf::scheduler::FIFORunner runner;
-    senf::scheduler::TimerDispatcher dispatcher (manager, runner);
-    manager.timeout(1000);
+    senf::scheduler::TimerDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance());
+    senf::scheduler::FdManager::instance().timeout(1000);
 
     senf::ClockService::clock_type t (senf::ClockService::now());
     senf::scheduler::TimerDispatcher::timer_id id;
     SENF_CHECK_NO_THROW(
         id = dispatcher.add( "testTimer", t + senf::ClockService::milliseconds(500), &handler ) );
     SENF_CHECK_NO_THROW( dispatcher.unblockSignals() );
-    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
     SENF_CHECK_NO_THROW( dispatcher.blockSignals() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     senf::ClockService::clock_type t2 (senf::ClockService::now());
     BOOST_CHECK( called );
     BOOST_CHECK_PREDICATE( is_close, (t2-t)(senf::ClockService::milliseconds(500)) );
@@ -75,9 +73,9 @@ BOOST_AUTO_UNIT_TEST(timerDispatcher)
     t = senf::ClockService::now();
     SENF_CHECK_NO_THROW( dispatcher.add( "testTimer", t, &handler ) );
     SENF_CHECK_NO_THROW( dispatcher.unblockSignals() );
-    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
     SENF_CHECK_NO_THROW( dispatcher.blockSignals() );
-    SENF_CHECK_NO_THROW( runner.run() );
+    SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
     BOOST_CHECK_PREDICATE( is_close, (t) (senf::ClockService::now()) );
     BOOST_CHECK( called );
 }
index 708faca..19673af 100644 (file)
@@ -377,6 +377,8 @@ prefix_ void senf::Daemon::fork()
         LIBC_CALL( ::close, (cerrpipe[1]) );
         LIBC_CALL( ::setsid, () );
         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
+
+        senf::Scheduler::instance().restart();
         return;
     }
 
@@ -386,6 +388,8 @@ prefix_ void senf::Daemon::fork()
     LIBC_CALL( ::close, (coutpipe[1]) );
     LIBC_CALL( ::close, (cerrpipe[1]) );
 
+    senf::Scheduler::instance().restart();
+
     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
     watcher.run();
 
@@ -558,6 +562,7 @@ 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)),
       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), 
       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) 
 {
@@ -571,7 +576,6 @@ 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();
 }
 
@@ -588,8 +592,8 @@ 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()");
+        if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
+            SENF_THROW_SYSTEM_EXCEPTION("::kill()");
         Scheduler::instance().timeout(
             Scheduler::instance().eventTime() + ClockService::seconds(1),
             senf::membind(&DaemonWatcher::childOk, this));
@@ -611,10 +615,10 @@ 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));
 }
 
index 0cc5c17..3dec5e2 100644 (file)
@@ -32,6 +32,7 @@
 #include <boost/utility.hpp>
 #include <boost/function.hpp>
 #include "../../Scheduler/Scheduler.hh"
+#include "../../Scheduler/SignalEvent.hh"
 
 ///////////////////////////////ih.p////////////////////////////////////////
 
@@ -93,6 +94,7 @@ namespace detail {
         int stderr_;
         bool sigChld_;
 
+        scheduler::SignalEvent cldSignal_;
         Forwarder coutForwarder_;
         Forwarder cerrForwarder_;
     };
index 7591434..cdf74b8 100644 (file)
@@ -36,6 +36,7 @@
 #include "Daemon.hh"
 #include "../Utils/Exception.hh"
 #include "../Utils/Backtrace.hh"
+#include "../Scheduler/Scheduler.hh"
 
 #include "../Utils/auto_unit_test.hh"
 #include <boost/test/test_tools.hpp>
@@ -100,11 +101,17 @@ namespace {
             } catch (...) {
                 std::cerr << "Unexpected exception" << std::endl;
             }
-            ::_exit(2);
+            ::_exit(125);
         }
         int status;
-        if (::waitpid(pid, &status, 0) < 0) throw senf::SystemException("::waitpid()");
-        return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+        if (::waitpid(pid, &status, 0) < 0) 
+            throw senf::SystemException("::waitpid()");
+        if (WIFSIGNALED(status))
+            std::cerr << "Terminated with signal " 
+                      << senf::signalName(WTERMSIG(status)) << "(" << WTERMSIG(status) << ")\n";
+        else if (WIFEXITED(status))
+            std::cerr << "Exited normally with exit status " << WEXITSTATUS(status) << "\n";
+        return status;
     }
 
 }
@@ -112,28 +119,29 @@ namespace {
 BOOST_AUTO_UNIT_TEST(testDaemon)
 {
     char * args[] = { "run", 
-                      "--console-log=testDaemon.log,none", 
+                      "--console-log=testDaemon.log", 
                       "--pid-file=testDaemon.pid" };
     BOOST_CHECK_EQUAL( run(sizeof(args)/sizeof(*args),args), 0 );
 
     BOOST_CHECK( ! boost::filesystem::exists("invalid.log") );
     BOOST_CHECK( ! boost::filesystem::exists("invalid.pid") );
-    BOOST_REQUIRE( boost::filesystem::exists("testDaemon.pid") );
+    BOOST_CHECK( boost::filesystem::exists("testDaemon.pid") );
     BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log") );
     
     boost::filesystem::rename("testDaemon.log", "testDaemon.log.1");
     {
         std::ifstream pidFile ("testDaemon.pid");
         int pid (0);
-        BOOST_REQUIRE( pidFile >> pid );
-        BOOST_REQUIRE( pid != 0 );
-        ::kill(pid, SIGHUP);
+        BOOST_CHECK( pidFile >> pid );
+        BOOST_CHECK( pid != 0 );
+        if (pid != 0)
+            ::kill(pid, SIGHUP);
     }
 
     delay(1000);
     BOOST_CHECK( ! boost::filesystem::exists("testDaemon.pid") );
     BOOST_CHECK( boost::filesystem::exists("testDaemon.log") );
-    BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log.1") );
+    BOOST_CHECK( boost::filesystem::exists("testDaemon.log.1") );
     
     std::ifstream log ("testDaemon.log.1");
     std::stringstream data;
index d124468..79dd1f7 100644 (file)
 ///////////////////////////////cti.p///////////////////////////////////////
 
 template <class Self>
+prefix_ senf::singleton<Self>::singleton()
+{
+    alive_ = true;
+}
+
+template <class Self>
+prefix_ senf::singleton<Self>::~singleton()
+{
+    alive_ = false;
+}
+
+template <class Self>
+bool senf::singleton<Self>::alive_ (false);
+
+template <class Self>
 prefix_ Self & senf::singleton<Self>::instance()
 {
     static Self instance_;
@@ -40,6 +55,12 @@ prefix_ Self & senf::singleton<Self>::instance()
 }
 
 template <class Self>
+prefix_ bool senf::singleton<Self>::alive()
+{
+    return alive_;
+}
+
+template <class Self>
 prefix_ senf::singleton<Self>::force_creation::force_creation()
 {
     // Force execution of instance() thereby creating instance
index 831e812..dce43c0 100644 (file)
@@ -88,7 +88,11 @@ namespace senf {
         : boost::noncopyable
     {
     protected:
+        singleton();
+        ~singleton();
+
         static Self & instance();       ///< Return singleton instance
+        static bool alive();            ///< Return \c true, if instance ok, \c false otherwise
 
     private:
         /** \brief Internal
@@ -101,6 +105,7 @@ namespace senf {
         };
 
         static force_creation creator_;
+        static bool alive_;
     };
 
 }
index 2d1fedd..781d434 100644 (file)
@@ -27,6 +27,7 @@
 //#include "singleton.test.ih"
 
 // Custom includes
+#include <iostream>
 #include "singleton.hh"
 
 #include "../Utils/auto_unit_test.hh"
@@ -47,6 +48,7 @@ namespace {
 
     public:
         using senf::singleton<Test>::instance;
+        using senf::singleton<Test>::alive;
 
         int foo() { return foo_; }
     };
@@ -55,6 +57,73 @@ namespace {
 BOOST_AUTO_UNIT_TEST(sInGlEtOn)
 {
     BOOST_CHECK_EQUAL( Test::instance().foo(), 1234 );
+    BOOST_CHECK( Test::alive() );
+}
+
+namespace {
+
+    bool test1Dead (false);
+    bool test2Dead (false);
+
+    bool test1Alive (false);
+    bool test2Alive (false);
+
+    struct AliveTest1 : public senf::singleton<AliveTest1>
+    {
+        friend class senf::singleton<AliveTest1>;
+        using senf::singleton<AliveTest1>::alive;
+        using senf::singleton<AliveTest1>::instance;
+        AliveTest1();
+        ~AliveTest1();
+    };
+
+    struct AliveTest2 : public senf::singleton<AliveTest2>
+    {
+        friend class senf::singleton<AliveTest2>;
+        using senf::singleton<AliveTest2>::alive;
+        using senf::singleton<AliveTest2>::instance;
+        AliveTest2();
+        ~AliveTest2();
+    };
+
+    AliveTest1::AliveTest1() 
+    {
+        test2Alive = AliveTest2::alive();
+    }
+
+    AliveTest1::~AliveTest1()
+    {
+        if (test2Dead) {
+            assert( ! AliveTest2::alive() );
+            std::cerr << "singleton alive test ok\n";
+        }
+        test1Dead = true;
+    }
+
+    AliveTest2::AliveTest2()
+    {
+        test1Alive = AliveTest1::alive();
+    }
+
+    AliveTest2::~AliveTest2()
+    {
+        if (test1Dead) {
+            assert( ! AliveTest1::alive() );
+            std::cerr << "singleton alive test ok\n";
+        }
+        test2Dead = true;
+    }
+
+}
+
+BOOST_AUTO_UNIT_TEST(singletonAlive)
+{
+    (void) AliveTest1::instance();
+    (void) AliveTest2::instance();
+
+    BOOST_CHECK( (test1Alive && !test2Alive) || (!test1Alive && test2Alive) );
+    BOOST_CHECK( AliveTest1::alive() );
+    BOOST_CHECK( AliveTest2::alive() );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 34d3617..f1037f6 100644 (file)
@@ -1,4 +1,5 @@
 import os, os.path, sys
+from cStringIO import StringIO
 from SCons.Script import *
 import SCons.Scanner.C
 
@@ -14,13 +15,18 @@ def scanTests(f):
         elif line.startswith('}') and name and start:
             tests[name] = (start, linenr)
     return tests
-            
+
 def CompileCheck(target, source, env):
     tests = scanTests(file(source[0].abspath))
-    errf = os.popen(env.subst('$CXXCOM -DCOMPILE_CHECK 2>&1', source=source, target=target))
+    cenv = env.Clone()
+    cenv.Append( CPPDEFINES = { 'COMPILE_CHECK': '' } )
+    out = StringIO()
+    cenv['SPAWN'] = lambda sh, escape, cmd, args, env, pspawn=cenv['PSPAWN'], out=out: \
+                    pspawn(sh, escape, cmd, args, env, out, out)
+    Action('$CXXCOM').execute(target, source, cenv)
     passedTests = {}
     delay_name = None
-    for error in errf:
+    for error in out.getvalue().splitlines():
         elts = error.split(':',2)
         if len(elts) != 3 : continue
         filename, line, message = elts
index 60e175a..15414fd 100644 (file)
@@ -253,7 +253,7 @@ def MakeEnvironment():
         # The boost-regex library is not compiled with _GLIBCXX_DEBUG so this fails:
         #          CPPDEFINES = [ '_GLIBCXX_DEBUG' ],
         env.Append(CXXFLAGS = [ '-O0', '-g' ],
-                   CPPDEFINES = [ 'SENF_DEBUG' ],
+                   CPPDEFINES = { 'SENF_DEBUG': ''},
                    LINKFLAGS = [ '-g', '-rdynamic' ])
 
     env.Append(CPPDEFINES = [ '$EXTRA_DEFINES' ],
index 249a78d..c704a1f 100644 (file)
@@ -23,7 +23,7 @@ def SetupForSENF(env):
     def parseLogOption(value):
         stream, area, level = ( x.strip() for x in value.strip().split('|') )
         stream = ''.join('(%s)' % x for x in stream.split('::') )
-        if area : area = ''.join( '(%s)' % x for x in elts[1].split('::') )
+        if area : area = ''.join( '(%s)' % x for x in area.split('::') )
         else    : area = '(_)'
         return '(( %s,%s,%s ))' % (stream,area,level)