From 0358235e0c94587c0ea04ebd82a97c356d2f99e0 Mon Sep 17 00:00:00 2001 From: g0dil <g0dil@wiback.org> Date: Fri, 4 Jul 2008 18:21:06 +0000 Subject: [PATCH] Scheduler: Implement FileDispatcher --- Scheduler/FdDispatcher.cc | 46 ++++++------ Scheduler/FdDispatcher.hh | 2 - Scheduler/FileDispatcher.cc | 117 +++++++++++++++++++++++++++++++ Scheduler/FileDispatcher.cci | 66 +++++++++++++++++ Scheduler/FileDispatcher.hh | 115 ++++++++++++++++++++++++++++++ Scheduler/FileDispatcher.test.cc | 103 +++++++++++++++++++++++++++ 6 files changed, 424 insertions(+), 25 deletions(-) create mode 100644 Scheduler/FileDispatcher.cc create mode 100644 Scheduler/FileDispatcher.cci create mode 100644 Scheduler/FileDispatcher.hh create mode 100644 Scheduler/FileDispatcher.test.cc diff --git a/Scheduler/FdDispatcher.cc b/Scheduler/FdDispatcher.cc index a393be5e..7d033a31 100644 --- a/Scheduler/FdDispatcher.cc +++ b/Scheduler/FdDispatcher.cc @@ -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); diff --git a/Scheduler/FdDispatcher.hh b/Scheduler/FdDispatcher.hh index e586592b..696be2a3 100644 --- a/Scheduler/FdDispatcher.hh +++ b/Scheduler/FdDispatcher.hh @@ -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 index 00000000..1989c90f --- /dev/null +++ b/Scheduler/FileDispatcher.cc @@ -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" + + +// 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 index 00000000..7d932d11 --- /dev/null +++ b/Scheduler/FileDispatcher.cci @@ -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_ + + +// 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 index 00000000..cd4b8841 --- /dev/null +++ b/Scheduler/FileDispatcher.hh @@ -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 + + +// 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 index 00000000..045f125d --- /dev/null +++ b/Scheduler/FileDispatcher.test.cc @@ -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_ + + +// 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: -- GitLab