Scheduler: Implement IdleEvent
g0dil [Mon, 6 Jul 2009 11:08:49 +0000 (11:08 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1256 270642c3-0616-0410-b53a-bc976706d245

Scheduler/FdEvent.ih
Scheduler/FdManager.hh
Scheduler/IdleEvent.cc [new file with mode: 0644]
Scheduler/IdleEvent.cci [new file with mode: 0644]
Scheduler/IdleEvent.hh [new file with mode: 0644]
Scheduler/IdleEvent.ih [new file with mode: 0644]
Scheduler/IdleEvent.test.cc [new file with mode: 0644]
Scheduler/Scheduler.cc
Scheduler/Scheduler.hh
Scheduler/TimerSource.cc

index 940a057..6e2cacd 100644 (file)
@@ -91,6 +91,7 @@ namespace detail {
 
         void prepareRun();
 
+        // Called by IdleEventDispatcher
         void timeout(int t);
         int timeout() const;
 
index ce34bfa..a87a91c 100644 (file)
@@ -61,11 +61,11 @@ namespace detail {
 
         bool set(int fd, int events, Event * entry);
         void remove(int fd);
-        void timeout(int t);            ///< Set event timeout
-                                        /**< proceseOnce() will wait for max \a t milliseconds for
-                                             an event to occur. If set to -1, processOnce() will
-                                             wait forever. */
+
+        // Called by FileDispatcher
+        void timeout(int t);
         int timeout() const;
+
         void processOnce();             ///< Wait for events
                                         /**< This call waits until at least one event is posted but
                                              no longer than the current timeout(). */
diff --git a/Scheduler/IdleEvent.cc b/Scheduler/IdleEvent.cc
new file mode 100644 (file)
index 0000000..daaef4a
--- /dev/null
@@ -0,0 +1,94 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// 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 IdleEvent non-inline non-template implementation */
+
+#include "IdleEvent.hh"
+#include "IdleEvent.ih"
+
+// Custom includes
+
+//#include "IdleEvent.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::IdleEvent
+
+prefix_ void senf::scheduler::IdleEvent::v_run()
+{
+    cb_();
+}
+
+prefix_ char const * senf::scheduler::IdleEvent::v_type()
+    const
+{
+    return "id";
+}
+
+prefix_ std::string senf::scheduler::IdleEvent::v_info()
+    const
+{
+    return "";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::IdleEventDispatcher
+
+prefix_ void senf::scheduler::detail::IdleEventDispatcher::remove(IdleEvent & event)
+{
+    EventList::iterator i (EventList::current(event));
+    if (i == events_.end())
+        return;
+    FIFORunner::instance().dequeue(&event);
+    events_.erase(i);
+    if (events_.empty())
+        detail::FileDispatcher::instance().timeout(managerTimeout_);
+}
+
+prefix_ void senf::scheduler::detail::IdleEventDispatcher::prepareRun()
+{
+    for (EventList::iterator i (events_.begin()), i_end (events_.end()); i != i_end; ++i)
+        i->setRunnable();
+}
+
+prefix_ senf::scheduler::detail::IdleEventDispatcher::~IdleEventDispatcher()
+{
+    for (EventList::iterator i (events_.begin()), i_end (events_.end()); i != i_end; ++i)
+        FIFORunner::instance().dequeue(&(*i));
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "IdleEvent.mpp"
+
+\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/IdleEvent.cci b/Scheduler/IdleEvent.cci
new file mode 100644 (file)
index 0000000..71e82e7
--- /dev/null
@@ -0,0 +1,115 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// 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 IdleEvent inline non-template implementation */
+
+#include "IdleEvent.ih"
+
+// Custom includes
+#include "FdEvent.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::IdleEvent
+
+prefix_ senf::scheduler::IdleEvent::IdleEvent(std::string const & name, Callback const & cb,
+                                              bool initiallyEnabled)
+    : detail::FIFORunner::TaskInfo(name), cb_ (cb)
+{
+    if (initiallyEnabled)
+        enable();
+}
+
+prefix_ senf::scheduler::IdleEvent::~IdleEvent()
+{
+    if (detail::IdleEventDispatcher::alive())
+        disable();
+}
+
+prefix_ void senf::scheduler::IdleEvent::disable()
+{
+    if (enabled())
+        detail::IdleEventDispatcher::instance().remove(*this);
+}
+
+prefix_ void senf::scheduler::IdleEvent::enable()
+{
+    if (! enabled()) {
+        detail::IdleEventDispatcher::instance().add(*this);
+        setRunnable();
+    }
+}
+
+prefix_ void senf::scheduler::IdleEvent::action(Callback const & cb)
+{
+    cb_ = cb;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::IdleEventDispatcher
+
+prefix_ void senf::scheduler::detail::IdleEventDispatcher::add(IdleEvent & event)
+{
+    events_.push_back(event);
+    FIFORunner::instance().enqueue(&event);
+    detail::FileDispatcher::instance().timeout(0);
+}
+
+prefix_ void senf::scheduler::detail::IdleEventDispatcher::timeout(int t)
+{
+    managerTimeout_ = t;
+    if (events_.empty())
+        detail::FileDispatcher::instance().timeout(managerTimeout_);
+}
+
+prefix_ int senf::scheduler::detail::IdleEventDispatcher::timeout()
+    const
+{
+    return managerTimeout_;
+}
+
+prefix_ bool senf::scheduler::detail::IdleEventDispatcher::empty()
+    const
+{
+    return events_.empty();
+}
+
+prefix_ senf::scheduler::detail::IdleEventDispatcher::IdleEventDispatcher()
+    : managerTimeout_ (scheduler::detail::FileDispatcher::instance().timeout())
+{}
+
+/////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\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/IdleEvent.hh b/Scheduler/IdleEvent.hh
new file mode 100644 (file)
index 0000000..de079c6
--- /dev/null
@@ -0,0 +1,101 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// 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 IdleEvent public header */
+
+#ifndef HH_SENF_Scheduler_IdleEvent_
+#define HH_SENF_Scheduler_IdleEvent_ 1
+
+// Custom includes
+#include <boost/function.hpp>
+#include "../boost/intrusive/ilist_hook.hpp"
+#include "FIFORunner.hh"
+
+//#include "IdleEvent.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace scheduler {
+
+namespace detail {
+    struct IdleEventListTag;
+    typedef boost::intrusive::ilist_base_hook<IdleEventListTag> IdleEventListBase;
+    class IdleEventDispatcher;
+}
+
+    class IdleEvent
+        : public detail::FIFORunner::TaskInfo,
+          public detail::IdleEventListBase
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void ()> Callback;
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///\{
+        
+        IdleEvent(std::string const & name, Callback const & cb, 
+                  bool initiallyEnabled = true);
+        ~IdleEvent();
+
+        ///\}
+        ///////////////////////////////////////////////////////////////////////////
+
+        void disable();                 ///< Disable event
+        void enable();                  ///< Enable event
+
+        void action(Callback const & cb); ///< Change event callback
+
+    protected:
+
+    private:
+        virtual void v_run();
+        virtual char const * v_type() const;
+        virtual std::string v_info() const;
+
+        Callback cb_;
+        
+        friend class detail::IdleEventDispatcher;
+    };
+        
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "IdleEvent.cci"
+//#include "IdleEvent.ct"
+//#include "IdleEvent.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/IdleEvent.ih b/Scheduler/IdleEvent.ih
new file mode 100644 (file)
index 0000000..4f0728e
--- /dev/null
@@ -0,0 +1,87 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// 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 IdleEvent internal header */
+
+#ifndef IH_SENF_Scheduler_IdleEvent_
+#define IH_SENF_Scheduler_IdleEvent_ 1
+
+// Custom includes
+#include "../Utils/singleton.hh"
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace scheduler {
+
+    void restart();
+
+namespace detail {
+    
+    class IdleEventDispatcher
+        : public singleton<IdleEventDispatcher>
+    {
+    public:
+        using singleton<IdleEventDispatcher>::instance;
+        using singleton<IdleEventDispatcher>::alive;
+
+        void add(IdleEvent & event);
+        void remove(IdleEvent & event);
+        
+        void prepareRun();
+
+        // Called by PollTimerSource
+        void timeout(int t);
+        int timeout() const;
+
+        bool empty() const;
+
+    private:
+        IdleEventDispatcher();
+        ~IdleEventDispatcher();
+
+        typedef boost::intrusive::ilist<
+            IdleEventListBase::value_traits<IdleEvent>, false > EventList;
+
+        EventList events_;
+        int managerTimeout_;
+
+        friend void senf::scheduler::restart();
+        friend class singleton<IdleEventDispatcher>;
+    };
+
+}}}
+
+///////////////////////////////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:
diff --git a/Scheduler/IdleEvent.test.cc b/Scheduler/IdleEvent.test.cc
new file mode 100644 (file)
index 0000000..d84207d
--- /dev/null
@@ -0,0 +1,84 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// 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 IdleEvent.test unit tests */
+
+//#include "IdleEvent.test.hh"
+//#include "IdleEvent.test.ih"
+
+// Custom includes
+#include "Scheduler.hh"
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+    bool timeoutFlag (false);
+
+    void timeout()
+    {
+        timeoutFlag = true;
+        senf::scheduler::terminate();
+    }
+
+    unsigned calls (0u);
+
+    void cb()
+    {
+        if (++calls >= 4)
+            senf::scheduler::terminate();
+    }
+
+}
+
+BOOST_AUTO_UNIT_TEST(idleEvent)
+{
+    senf::scheduler::IdleEvent idle ("idle event unit test", &cb);
+
+    senf::scheduler::TimerEvent watchdog (
+        "IdleEvent unit test watchdog", &timeout,
+        senf::ClockService::now() + senf::ClockService::milliseconds(100));
+
+    senf::scheduler::process();
+
+    BOOST_CHECK( ! timeoutFlag );
+    BOOST_CHECK_EQUAL( calls, 4u );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\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:
index a79307a..471b743 100644 (file)
@@ -92,15 +92,16 @@ prefix_ void senf::scheduler::process()
 {
     SchedulerScopedInit initScheduler;
     terminate_ = false;
-    running_ = true;
     detail::TimerDispatcher::instance().reschedule();
     while(! terminate_ && ! (detail::FdDispatcher::instance().empty() &&
                              detail::TimerDispatcher::instance().empty() &&
-                             detail::FileDispatcher::instance().empty())) {
+                             detail::FileDispatcher::instance().empty() &&
+                             detail::IdleEventDispatcher::instance().empty()) ) {
         detail::FdManager::instance().processOnce();
         detail::FileDispatcher::instance().prepareRun();
         detail::EventHookDispatcher::instance().prepareRun();
         detail::TimerDispatcher::instance().prepareRun();
+        detail::IdleEventDispatcher::instance().prepareRun();
         detail::FIFORunner::instance().run();
         detail::TimerDispatcher::instance().reschedule();
     }
@@ -114,9 +115,11 @@ prefix_ void senf::scheduler::restart()
     detail::TimerDispatcher*      tdd (&detail::TimerDispatcher::instance());
     detail::SignalDispatcher*     sdd (&detail::SignalDispatcher::instance());
     detail::FileDispatcher*       fld (&detail::FileDispatcher::instance());
+    detail::IdleEventDispatcher*  ied (&detail::IdleEventDispatcher::instance());
     detail::EventHookDispatcher*  eed (&detail::EventHookDispatcher::instance());
 
     eed->~EventHookDispatcher();
+    ied->~IdleEventDispatcher();
     fld->~FileDispatcher();
     sdd->~SignalDispatcher();
     tdd->~TimerDispatcher();
@@ -130,6 +133,7 @@ prefix_ void senf::scheduler::restart()
     new (tdd) detail::TimerDispatcher();
     new (sdd) detail::SignalDispatcher();
     new (fld) detail::FileDispatcher();
+    new (ied) detail::IdleEventDispatcher();
     new (eed) detail::EventHookDispatcher();
 }
 
@@ -139,6 +143,7 @@ prefix_ bool senf::scheduler::empty()
         && detail::TimerDispatcher::instance().empty()
         && detail::FileDispatcher::instance().empty()
         && detail::SignalDispatcher::instance().empty()
+        && detail::IdleEventDispatcher::instance().empty()
         && detail::EventHookDispatcher::instance().empty();
 }
 
@@ -160,7 +165,7 @@ prefix_ void senf::scheduler::hiresTimers()
 prefix_ senf::log::time_type senf::scheduler::LogTimeSource::operator()()
     const
 {
-    return eventTime();
+    return now();
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 62a687c..e1501a7 100644 (file)
@@ -33,6 +33,7 @@
 #include "FdEvent.hh"
 #include "TimerEvent.hh"
 #include "SignalEvent.hh"
+#include "IdleEvent.hh"
 #include "EventHook.hh"
 
 //#include "scheduler.mpp"
index 35e6a5a..df05438 100644 (file)
@@ -27,7 +27,7 @@
 //#include "TimerSource.ih"
 
 // Custom includes
-#include "FdEvent.hh"
+#include "IdleEvent.hh"
 #ifdef HAVE_TIMERFD
 #include <sys/timerfd.h>
 #endif
@@ -157,12 +157,12 @@ prefix_ void senf::scheduler::detail::PollTimerSource::timeout(ClockService::clo
 {
     ClockService::clock_type now (ClockService::now());
     int delay (ClockService::in_milliseconds(timeout-now)+1);
-    FileDispatcher::instance().timeout(delay<0?0:delay);
+    IdleEventDispatcher::instance().timeout(delay<0?0:delay);
 }
 
 prefix_ void senf::scheduler::detail::PollTimerSource::notimeout()
 {
-    FileDispatcher::instance().timeout(-1);
+    IdleEventDispatcher::instance().timeout(-1);
 }
 
 prefix_ void senf::scheduler::detail::PollTimerSource::enable()