Scheduler: Implement FileDispatcher
g0dil [Fri, 4 Jul 2008 18:21:06 +0000 (18:21 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@889 270642c3-0616-0410-b53a-bc976706d245

Scheduler/FdDispatcher.cc
Scheduler/FdDispatcher.hh
Scheduler/FileDispatcher.cc [new file with mode: 0644]
Scheduler/FileDispatcher.cci [new file with mode: 0644]
Scheduler/FileDispatcher.hh [new file with mode: 0644]
Scheduler/FileDispatcher.test.cc [new file with mode: 0644]

index a393be5..7d033a3 100644 (file)
@@ -64,29 +64,29 @@ prefix_ void senf::scheduler::FdDispatcher::add(int fd, Callback const & cb, int
     if (events & EV_PRIO) event.FdEvent::PrioTask::cb = cb;
     if (events & EV_WRITE) event.FdEvent::WriteTask::cb = cb;
 
-     manager_.set(fd, event.activeEvents(), &event);
- }
-
- prefix_ void senf::scheduler::FdDispatcher::remove(int fd, int events)
- {
-     if (events == 0)
-         return;
-
-     FdMap::iterator i (fds_.find(fd));
-     if (i == fds_.end())
-         return;
-     FdEvent & event (i->second);
-
-     if (events & EV_READ) event.FdEvent::ReadTask::cb = 0;
-     if (events & EV_PRIO) event.FdEvent::PrioTask::cb = 0;
-     if (events & EV_WRITE) event.FdEvent::WriteTask::cb = 0;
-
-     int activeEvents (event.activeEvents());
-     if (! activeEvents) {
-         manager_.remove(fd);
-         runner_.dequeue(static_cast<FdEvent::ReadTask*>(&i->second));
-         runner_.dequeue(static_cast<FdEvent::PrioTask*>(&i->second));
-         runner_.dequeue(static_cast<FdEvent::WriteTask*>(&i->second));
+    manager_.set(fd, event.activeEvents(), &event);
+}
+
+prefix_ void senf::scheduler::FdDispatcher::remove(int fd, int events)
+{
+    if (events == 0)
+        return;
+
+    FdMap::iterator i (fds_.find(fd));
+    if (i == fds_.end())
+        return;
+    FdEvent & event (i->second);
+
+    if (events & EV_READ) event.FdEvent::ReadTask::cb = 0;
+    if (events & EV_PRIO) event.FdEvent::PrioTask::cb = 0;
+    if (events & EV_WRITE) event.FdEvent::WriteTask::cb = 0;
+
+    int activeEvents (event.activeEvents());
+    if (! activeEvents) {
+        manager_.remove(fd);
+        runner_.dequeue(static_cast<FdEvent::ReadTask*>(&i->second));
+        runner_.dequeue(static_cast<FdEvent::PrioTask*>(&i->second));
+        runner_.dequeue(static_cast<FdEvent::WriteTask*>(&i->second));
         fds_.erase(fd);
     } else
         manager_.set(fd, activeEvents, &event);
index e586592..696be2a 100644 (file)
@@ -81,9 +81,7 @@ namespace scheduler {
             typedef detail::FdTask<2, FdEvent> WriteTask;
 
             virtual void signal(int events);
-
             int activeEvents() const;
-
             int events;
         };
 
diff --git a/Scheduler/FileDispatcher.cc b/Scheduler/FileDispatcher.cc
new file mode 100644 (file)
index 0000000..1989c90
--- /dev/null
@@ -0,0 +1,117 @@
+// $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 FileDispatcher non-inline non-template implementation */
+
+#include "FileDispatcher.hh"
+//#include "FileDispatcher.ih"
+
+// Custom includes
+
+//#include "FileDispatcher.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ senf::scheduler::FileDispatcher::FileDispatcher(FdManager & manager,
+                                                        FIFORunner & runner)
+    : manager_ (manager), runner_ (runner), managerTimeout_ (manager.timeout())
+{}
+
+prefix_ senf::scheduler::FileDispatcher::~FileDispatcher()
+{
+    manager_.timeout(-1);
+
+    for (FileMap::iterator i (files_.begin()); i != files_.end(); ++i) {
+        runner_.dequeue(static_cast<FileEvent::ReadTask*>(&i->second));
+        runner_.dequeue(static_cast<FileEvent::WriteTask*>(&i->second));
+    }
+}
+
+prefix_ void senf::scheduler::FileDispatcher::add(int fd, Callback const & cb, int events)
+{
+    if (events == 0)
+        return;
+    
+    FileMap::iterator i (files_.find(fd));
+    if (i == files_.end()) {
+        i = files_.insert(std::make_pair(fd, FileEvent())).first;
+        runner_.enqueue(static_cast<FileEvent::ReadTask*>(&i->second));
+        runner_.enqueue(static_cast<FileEvent::WriteTask*>(&i->second));
+    }
+    FileEvent & event (i->second);
+
+    if (events & EV_READ) event.FileEvent::ReadTask::cb = cb;
+    if (events & EV_WRITE) event.FileEvent::WriteTask::cb = cb;
+    
+    manager_.timeout(0);
+}
+
+prefix_ void senf::scheduler::FileDispatcher::remove(int fd, int events)
+{
+    if (events == 0)
+        return;
+
+    FileMap::iterator i (files_.find(fd));
+    if (i == files_.end()) 
+        return;
+    FileEvent & event (i->second);
+
+    if (events & EV_READ) event.FileEvent::ReadTask::cb = 0;
+    if (events & EV_WRITE) event.FileEvent::WriteTask::cb = 0;
+
+    int activeEvents (event.activeEvents());
+    if (! activeEvents) {
+        runner_.dequeue(static_cast<FileEvent::ReadTask*>(&i->second));
+        runner_.dequeue(static_cast<FileEvent::WriteTask*>(&i->second));
+        files_.erase(fd);
+    }
+    
+    if (files_.empty())
+        manager_.timeout(managerTimeout_);
+}
+
+prefix_ void senf::scheduler::FileDispatcher::prepareRun()
+{
+    for (FileMap::iterator i (files_.begin()); i != files_.end(); ++i) {
+        i->second.events = i->second.activeEvents();
+        if (i->second.FileEvent::ReadTask::cb)
+            i->second.FileEvent::ReadTask::runnable = true;
+        if (i->second.FileEvent::WriteTask::cb)
+            i->second.FileEvent::WriteTask::runnable = true;
+    }
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "FileDispatcher.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/FileDispatcher.cci b/Scheduler/FileDispatcher.cci
new file mode 100644 (file)
index 0000000..7d932d1
--- /dev/null
@@ -0,0 +1,66 @@
+// $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 FileDispatcher inline non-template implementation */
+
+//#include "FileDispatcher.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ int senf::scheduler::FileDispatcher::FileEvent::activeEvents()
+    const
+{
+    return 
+        (ReadTask::cb ? EV_READ : 0) | 
+        (WriteTask::cb ? EV_WRITE : 0);
+}
+
+prefix_ void senf::scheduler::FileDispatcher::timeout(int t)
+{
+    managerTimeout_ = t;
+    if (files_.empty())
+        manager_.timeout(managerTimeout_);
+}
+
+prefix_ int senf::scheduler::FileDispatcher::timeout()
+    const
+{
+    return managerTimeout_;
+}
+
+///////////////////////////////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/FileDispatcher.hh b/Scheduler/FileDispatcher.hh
new file mode 100644 (file)
index 0000000..cd4b884
--- /dev/null
@@ -0,0 +1,115 @@
+// $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 FileDispatcher public header */
+
+#ifndef HH_FileDispatcher_
+#define HH_FileDispatcher_ 1
+
+// Custom includes
+#include <map>
+#include "FdManager.hh"
+#include "FIFORunner.hh"
+#include "FdDispatcher.hh"
+
+//#include "FileDispatcher.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace scheduler {
+
+    /** \brief
+      */
+    class FileDispatcher
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void (int)> Callback;
+
+        enum Events { 
+            EV_READ = FdManager::EV_READ, EV_WRITE = FdManager::EV_WRITE,
+            EV_HUP = FdManager::EV_HUP, EV_ERR = FdManager::EV_ERR,
+            EV_ALL = FdManager::EV_READ | FdManager::EV_WRITE
+        };
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        FileDispatcher(FdManager & manager, FIFORunner & runner);
+        ~FileDispatcher();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+        
+        void add(int fd, Callback const & cb, int events = EV_ALL);
+        void remove(int fd, int events = EV_ALL);
+
+        void prepareRun();
+
+        void timeout(int t);
+        int timeout() const;
+
+    protected:
+
+    private:
+        struct FileEvent
+            : public detail::FdTask<0, FileEvent>,
+              public detail::FdTask<1, FileEvent>
+        {
+            typedef detail::FdTask<0, FileEvent> ReadTask;
+            typedef detail::FdTask<1, FileEvent> WriteTask;
+
+            int activeEvents() const;
+            int events;
+        };
+
+        typedef std::map<int, FileEvent> FileMap;
+
+        FileMap files_;
+        FdManager & manager_;
+        FIFORunner & runner_;
+        int managerTimeout_;
+    };
+
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "FileDispatcher.cci"
+//#include "FileDispatcher.ct"
+//#include "FileDispatcher.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/FileDispatcher.test.cc b/Scheduler/FileDispatcher.test.cc
new file mode 100644 (file)
index 0000000..045f125
--- /dev/null
@@ -0,0 +1,103 @@
+// $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 FileDispatcher.test unit tests */
+
+//#include "FileDispatcher.test.hh"
+//#include "FileDispatcher.test.ih"
+
+// Custom includes
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "FileDispatcher.hh"
+#include "ClockService.hh"
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+    bool is_close(senf::ClockService::clock_type a, senf::ClockService::clock_type b)
+    {
+        return (a<b ? b-a : a-b) < senf::ClockService::milliseconds(100);
+    }
+
+    bool called (false);
+    void handler(int events)
+    {
+        called=true;
+    }
+}
+
+BOOST_AUTO_UNIT_TEST(fileDispatcher)
+{
+    senf::scheduler::FdManager manager;
+    senf::scheduler::FIFORunner runner;
+    senf::scheduler::FileDispatcher dispatcher (manager, runner);
+    dispatcher.timeout(500);
+
+    // It's not necessary for the cb to be a real file .. it can be anything. The only thing is,
+    // it's always called without delay.
+    int fd (open("/dev/null", O_RDWR));
+    
+    senf::ClockService::clock_type t (senf::ClockService::now());
+    SENF_CHECK_NO_THROW( dispatcher.add(fd, &handler, senf::scheduler::FileDispatcher::EV_READ) );
+    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( dispatcher.prepareRun() );
+    SENF_CHECK_NO_THROW( runner.run() );
+    
+    BOOST_CHECK( called );
+    BOOST_CHECK_PREDICATE( is_close, (t)(senf::ClockService::now()) );
+
+    SENF_CHECK_NO_THROW( dispatcher.remove(fd) );
+    close(fd);
+
+    called = false;
+    t = senf::ClockService::now();
+    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( dispatcher.prepareRun() );
+    SENF_CHECK_NO_THROW( runner.run() );
+
+    BOOST_CHECK( ! called );
+    BOOST_CHECK_PREDICATE( 
+        is_close, (t+senf::ClockService::milliseconds(500))(senf::ClockService::now()) );
+}
+
+///////////////////////////////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: