From: g0dil Date: Mon, 20 Oct 2008 20:28:51 +0000 (+0000) Subject: PPI: Delayed connect and disconnect X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=c7ddbbb0bc014bdfe6daef91e2d1c512d77e9fff;p=senf.git PPI: Delayed connect and disconnect Scheduler: EventEvent hook Scheduler: Simple task priorities git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@940 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/PPI/Connectors.cc b/PPI/Connectors.cc index ab1a038..a39857e 100644 --- a/PPI/Connectors.cc +++ b/PPI/Connectors.cc @@ -53,8 +53,23 @@ prefix_ void senf::ppi::connector::Connector::connect(Connector & target) peer_ = & target; target.peer_ = this; - if (ModuleManager::instance().running()) - v_init(); + if (! initializationScheduled()) + enqueueInitializable(); + if (! peer().initializationScheduled()) + peer().enqueueInitializable(); +} + +prefix_ void senf::ppi::connector::Connector::disconnect() +{ + SENF_ASSERT( peer_ ); + Connector & peer (*peer_); + peer_ = 0; + peer.peer_ = 0; + + if (! initializationScheduled()) + enqueueInitializable(); + if (! peer.initializationScheduled()) + peer.enqueueInitializable(); } prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID() diff --git a/PPI/Connectors.cci b/PPI/Connectors.cci index 12c14a1..0896001 100644 --- a/PPI/Connectors.cci +++ b/PPI/Connectors.cci @@ -56,8 +56,11 @@ prefix_ senf::ppi::connector::Connector::Connector() prefix_ senf::ppi::connector::Connector::~Connector() { - if (connected()) + if (connected()) { + Connector & peer (*peer_); peer_->peer_ = 0; + peer.v_init(); + } } prefix_ bool senf::ppi::connector::Connector::connected() @@ -74,11 +77,6 @@ prefix_ void senf::ppi::connector::Connector::setModule(module::Module & module) module_ = &module; } -prefix_ void senf::ppi::connector::Connector::init() -{ - v_init(); -} - /////////////////////////////////////////////////////////////////////////// // senf::ppi::connector::PassiveConnector diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh index 0874551..e5ea9c9 100644 --- a/PPI/Connectors.hh +++ b/PPI/Connectors.hh @@ -36,6 +36,7 @@ #include "predecl.hh" #include "detail/Callback.hh" #include "Queueing.hh" +#include "ModuleManager.hh" //#include "Connectors.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -122,7 +123,7 @@ namespace connector { to the containing module) */ class Connector - : boost::noncopyable + : ModuleManager::Initializable, boost::noncopyable { public: Connector & peer() const; ///< Get peer connected to this connector @@ -130,6 +131,8 @@ namespace connector { bool connected() const; ///< \c true, if connector connected, \c false otherwise + void disconnect(); ///< Disconnect connector from peer + protected: Connector(); virtual ~Connector(); @@ -140,8 +143,6 @@ namespace connector { virtual std::type_info const & packetTypeID(); void setModule(module::Module & module); - void init(); - virtual void v_init() = 0; Connector * peer_; module::Module * module_; diff --git a/PPI/Connectors.test.cc b/PPI/Connectors.test.cc index 6b95fc2..2e599ba 100644 --- a/PPI/Connectors.test.cc +++ b/PPI/Connectors.test.cc @@ -421,6 +421,123 @@ BOOST_AUTO_UNIT_TEST(connectorTest) } } +BOOST_AUTO_UNIT_TEST(delayedConnect) +{ + { + debug::PassiveSource source; + debug::ActiveSink target; + + ppi::init(); + + BOOST_CHECK( ! target.input ); + BOOST_CHECK( ! target.request() ); + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( ! target.input ); + + senf::Packet p (senf::DataPacket::create()); + source.submit(p); + BOOST_CHECK( target.request() == p ); + } + + { + debug::PassiveSource source; + debug::ActiveSink target; + + ppi::init(); + + senf::Packet p (senf::DataPacket::create()); + source.submit(p); + + BOOST_CHECK( ! target.input ); + BOOST_CHECK( ! target.request() ); + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( target.input ); + BOOST_CHECK( target.request() == p ); + } + + { + debug::ActiveSource source; + debug::PassiveSink target; + + ppi::init(); + + BOOST_CHECK( ! source.output ); + SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) ); + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( source.output ); + + senf::Packet p (senf::DataPacket::create()); + source.submit(p); + + BOOST_CHECK( target.front() == p ); + BOOST_CHECK_EQUAL( target.size(), 1u ); + } + + { + debug::ActiveSource source; + debug::PassiveSink target; + + ppi::init(); + + BOOST_CHECK( ! source.output ); + SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) ); + target.throttle(); + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( ! source.output ); + target.unthrottle(); + BOOST_CHECK( source.output ); + } +} + +BOOST_AUTO_UNIT_TEST(disconnect) +{ + { + debug::PassiveSource source; + debug::ActiveSink target; + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( ! target.input ); + + senf::Packet p (senf::DataPacket::create()); + source.submit(p); + + BOOST_CHECK( target.input ); + + target.input.disconnect(); + ppi::init(); + + BOOST_CHECK( ! target.input ); + } + { + debug::ActiveSource source; + debug::PassiveSink target; + + ppi::connect(source, target); + ppi::init(); + + BOOST_CHECK( source.output ); + + source.output.disconnect(); + ppi::init(); + + BOOST_CHECK( ! source.output ); + } +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ diff --git a/PPI/Mainpage.dox b/PPI/Mainpage.dox index 5afa6e0..99d25a8 100644 --- a/PPI/Mainpage.dox +++ b/PPI/Mainpage.dox @@ -221,7 +221,7 @@ must be untyped (they accept arbitrary senf::Packet's, the optional tempalte argument is empty), or they both accept the same type of packet. This check is performed at runtime. - To complete our simplified example: Lets connet senf::ppi::module::ActiveSocketReader and + To complete our simplified example: Lets connect senf::ppi::module::ActiveSocketReader and senf::ppi::module::PassiveSocketWriter to our example module: \code diff --git a/PPI/Module.cci b/PPI/Module.cci index 6a7be73..de184f7 100644 --- a/PPI/Module.cci +++ b/PPI/Module.cci @@ -38,15 +38,6 @@ //////////////////////////////////////// // private members -prefix_ void senf::ppi::module::Module::init() -{ - ConnectorRegistry::iterator i (connectorRegistry_.begin()); - ConnectorRegistry::iterator i_end (connectorRegistry_.end()); - for (; i != i_end; ++i) - (*i)->init(); - v_init(); -} - prefix_ void senf::ppi::module::Module::v_init() {} diff --git a/PPI/Module.hh b/PPI/Module.hh index 9c19e6c..1062fb0 100644 --- a/PPI/Module.hh +++ b/PPI/Module.hh @@ -33,6 +33,7 @@ #include #include "../Scheduler/ClockService.hh" #include "predecl.hh" +#include "ModuleManager.hh" //#include "Module.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -167,7 +168,7 @@ namespace module { \see \ref ppi_modules */ class Module - : boost::noncopyable + : ModuleManager::Initializable, boost::noncopyable { public: virtual ~Module(); @@ -289,7 +290,6 @@ namespace module { private: #endif - void init(); virtual void v_init(); #ifndef DOXYGEN diff --git a/PPI/ModuleManager.cc b/PPI/ModuleManager.cc index 490bb01..91a4373 100644 --- a/PPI/ModuleManager.cc +++ b/PPI/ModuleManager.cc @@ -28,6 +28,7 @@ // Custom includes #include "../Scheduler/Scheduler.hh" +#include "../Utils/membind.hh" #include "Module.hh" //#include "ModuleManager.mpp" @@ -39,10 +40,11 @@ prefix_ void senf::ppi::ModuleManager::init() { - ModuleRegistry::const_iterator i (moduleRegistry_.begin()); - ModuleRegistry::const_iterator const i_end (moduleRegistry_.end()); - for (; i != i_end; ++i) - (*i)->init(); + while (! initQueue_.empty()) { + initQueue_.front()->v_init(); + initQueue_.pop_front(); + } + initRunner_.disable(); } #ifndef DOXYGEN @@ -67,7 +69,9 @@ prefix_ void senf::ppi::ModuleManager::run() // private members prefix_ senf::ppi::ModuleManager::ModuleManager() - : running_(false), terminate_(false) + : running_(false), terminate_(false), + initRunner_ ("senf::ppi::init", membind(&ModuleManager::init, this), false, + scheduler::EventEvent::PRIORITY_LOW) {} ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/PPI/ModuleManager.cci b/PPI/ModuleManager.cci index fc7f7f9..db78d85 100644 --- a/PPI/ModuleManager.cci +++ b/PPI/ModuleManager.cci @@ -50,12 +50,69 @@ prefix_ void senf::ppi::ModuleManager::unregisterModule(module::Module & module) moduleRegistry_.end()); } +prefix_ void senf::ppi::ModuleManager::registerInitializable(Initializable & i) +{ + initQueue_.push_back(&i); + initRunner_.enable(); +} + +prefix_ void senf::ppi::ModuleManager::unregisterInitializable(Initializable & i) +{ + initQueue_.erase( + std::remove(initQueue_.begin(), initQueue_.end(), & i), + initQueue_.end()); + if (initQueue_.empty()) + initRunner_.disable(); +} + +prefix_ bool senf::ppi::ModuleManager::initializableRegistered(Initializable const & i) + const +{ + return std::find(initQueue_.begin(), initQueue_.end(), &i) != initQueue_.end(); +} + prefix_ bool senf::ppi::ModuleManager::running() const { return running_; } +/////////////////////////////////////////////////////////////////////////// +// senf::ppi::ModuleManager::Initializable + +prefix_ senf::ppi::ModuleManager::Initializable::Initializable() +{ + enqueueInitializable(); +} + +prefix_ senf::ppi::ModuleManager::Initializable::~Initializable() +{ + dequeueInitializable(); +} + +prefix_ void senf::ppi::ModuleManager::Initializable::enqueueInitializable() +{ + moduleManager().registerInitializable(*this); +} + +prefix_ void senf::ppi::ModuleManager::Initializable::dequeueInitializable() +{ + moduleManager().unregisterInitializable(*this); +} + +prefix_ bool senf::ppi::ModuleManager::Initializable::initializationScheduled() + const +{ + return moduleManager().initializableRegistered(*this); +} + +prefix_ senf::ppi::ModuleManager::ModuleManager & +senf::ppi::ModuleManager::Initializable::moduleManager() + const +{ + return ModuleManager::instance(); +} + ///////////////////////////////cci.e/////////////////////////////////////// #undef prefix_ diff --git a/PPI/ModuleManager.hh b/PPI/ModuleManager.hh index 6c8d291..262dc4c 100644 --- a/PPI/ModuleManager.hh +++ b/PPI/ModuleManager.hh @@ -28,7 +28,9 @@ // Custom includes #include +#include #include "predecl.hh" +#include "../Scheduler/Scheduler.hh" //#include "ModuleManager.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -45,6 +47,21 @@ namespace ppi { { public: /////////////////////////////////////////////////////////////////////////// + // Types + + struct Initializable + { + Initializable(); + virtual ~Initializable(); + ModuleManager & moduleManager() const; + void enqueueInitializable(); + void dequeueInitializable(); + bool initializationScheduled() const; + + virtual void v_init() = 0; + }; + + /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///@{ @@ -71,7 +88,12 @@ namespace ppi { void registerModule(module::Module & module); void unregisterModule(module::Module & module); + void registerInitializable(Initializable & i); + void unregisterInitializable(Initializable & i); + bool initializableRegistered(Initializable const & i) const; + typedef std::vector ModuleRegistry; + typedef std::deque InitQueue; #ifndef DOXYGEN struct RunGuard; @@ -82,7 +104,12 @@ namespace ppi { bool running_; bool terminate_; + InitQueue initQueue_; + + scheduler::EventEvent initRunner_; + friend class module::Module; + friend class Initializable; }; diff --git a/PPI/Setup.cci b/PPI/Setup.cci index 5311aaa..127a45f 100644 --- a/PPI/Setup.cci +++ b/PPI/Setup.cci @@ -27,6 +27,7 @@ // Custom includes #include "Connectors.hh" +#include "Module.hh" #include "ModuleManager.hh" #define prefix_ inline diff --git a/Scheduler/EventEvent.cc b/Scheduler/EventEvent.cc new file mode 100644 index 0000000..f2d8097 --- /dev/null +++ b/Scheduler/EventEvent.cc @@ -0,0 +1,93 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EventEvent non-inline non-template implementation */ + +#include "EventEvent.hh" +#include "EventEvent.ih" + +// Custom includes + +//#include "EventEvent.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::EventEvent + +prefix_ void senf::scheduler::EventEvent::v_run() +{ + cb_(); +} + +prefix_ char const * senf::scheduler::EventEvent::v_type() + const +{ + return "ee"; +} + +prefix_ std::string senf::scheduler::EventEvent::v_info() + const +{ + return ""; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::EventEventDispatcher + +prefix_ senf::scheduler::detail::EventEventDispatcher::~EventEventDispatcher() +{ + for (EventList::iterator i (events_.begin()); i != events_.end(); ++i) + FIFORunner::instance().dequeue(&(*i)); +} + +prefix_ prefix_ void senf::scheduler::detail::EventEventDispatcher::remove(EventEvent & event) +{ + EventList::iterator i (EventList::current(event)); + if (i == events_.end()) + return; + FIFORunner::instance().dequeue(&event); + events_.erase(i); +} + +prefix_ void senf::scheduler::detail::EventEventDispatcher::prepareRun() +{ + for (EventList::iterator i (events_.begin()); i != events_.end(); ++i) + i->setRunnable(); +} + + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "EventEvent.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/EventEvent.cci b/Scheduler/EventEvent.cci new file mode 100644 index 0000000..9cb6ace --- /dev/null +++ b/Scheduler/EventEvent.cci @@ -0,0 +1,98 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EventEvent inline non-template implementation */ + +#include "EventEvent.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::EventEvent + +prefix_ senf::scheduler::EventEvent::EventEvent(std::string const & name, Callback const & cb, + bool initiallyEnabled, + detail::FIFORunner::TaskInfo::Priority priority) + : detail::FIFORunner::TaskInfo(name, priority), cb_ (cb) +{ + if (initiallyEnabled) + enable(); +} + +prefix_ senf::scheduler::EventEvent::~EventEvent() +{ + if (detail::EventEventDispatcher::alive()) + disable(); +} + +prefix_ void senf::scheduler::EventEvent::disable() +{ + if (enabled()) + detail::EventEventDispatcher::instance().remove(*this); +} + +prefix_ void senf::scheduler::EventEvent::enable() +{ + if (! enabled()) + detail::EventEventDispatcher::instance().add(*this); +} + +prefix_ void senf::scheduler::EventEvent::action(Callback const & cb) +{ + cb_ = cb; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::EventEventDispatcher + +prefix_ void senf::scheduler::detail::EventEventDispatcher::add(EventEvent & event) +{ + events_.push_back(event); + FIFORunner::instance().enqueue(&event); +} + +prefix_ bool senf::scheduler::detail::EventEventDispatcher::empty() + const +{ + return events_.empty(); +} + +prefix_ senf::scheduler::detail::EventEventDispatcher::EventEventDispatcher() +{} + +///////////////////////////////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/EventEvent.hh b/Scheduler/EventEvent.hh new file mode 100644 index 0000000..4b0b27f --- /dev/null +++ b/Scheduler/EventEvent.hh @@ -0,0 +1,136 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EventEvent public header */ + +#ifndef HH_EventEvent_ +#define HH_EventEvent_ 1 + +// Custom includes +#include +#include "../boost/intrusive/ilist_hook.hpp" +#include "FIFORunner.hh" + +//#include "EventEvent.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace scheduler { + + namespace detail { + struct EventEventListTag; + typedef boost::intrusive::ilist_base_hook EventEventListBase; + class EventEventDispatcher; + } + + /** \brief Event hook event + + This event is special: It is not a real event, it is a kind of hook which is called, + whenever any other event is signaled. Combining this with explicit priority specification, + this can be used to implement hooks which are called before or after any other callback. + + \code + void beforeEventHook(); + void afterEventHook(); + + senf::scheduler::EventEvent beforeEventHookEvent ( + "beforeEventHook", beforeEventHook, true, senf::scheduler::EventEvent::PRIORITY_LOW); + senf::scheduler::EventEvent afterEventHookEvent ( + "afterEventHook", afterEventHook, true, senf::scheduler::EventEvent::PRIORITY_HIGH); + \endcode + + This usage assumes, that all ordinary events are registered with \c PRIORITY_NORMAL. + + The EventEvent class is an implementation of the RAII idiom: The event will be automatically + unregistered in the EventEvent destructor. The EventEvent 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 EventEvent + : public detail::FIFORunner::TaskInfo, + public detail::EventEventListBase + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::function Callback; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + EventEvent(std::string const & name, Callback const & cb, + bool initiallyEnabled = true, Priority priority = PRIORITY_NORMAL); + ///< Register an event hook + /**< Registers \a cb to be called whenever any other event + is signaled by the scheduler. If \a initiallyEnabled is + set \c false, the callback will not be enabled + automatically. Use enable() to do so. + \param[in] name Descriptive event name (purely + informational) + \param[in] cb Callback to call + \param[in] initiallyEnabled if set \c false, do not + enable callback automatically. + \param[in] priority event priority, defaults to + PRIORITY_NORMAL */ + ~EventEvent(); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + 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::EventEventDispatcher; + }; + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "EventEvent.cci" +//#include "EventEvent.ct" +//#include "EventEvent.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.cci b/Scheduler/EventEvent.ih similarity index 53% rename from Scheduler/FileDispatcher.cci rename to Scheduler/EventEvent.ih index 388c3d1..823b50b 100644 --- a/Scheduler/FileDispatcher.cci +++ b/Scheduler/EventEvent.ih @@ -21,25 +21,54 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief FileDispatcher inline non-template implementation */ + \brief EventEvent internal header */ -#include "FileDispatcher.ih" +#ifndef IH_EventEvent_ +#define IH_EventEvent_ 1 // Custom includes +#include "../Utils/singleton.hh" -#define prefix_ inline -///////////////////////////////cci.p/////////////////////////////////////// +///////////////////////////////ih.p//////////////////////////////////////// -prefix_ int senf::scheduler::FileDispatcher::FileEvent::activeEvents() - const -{ - return - (ReadTask::cb ? EV_READ : 0) | - (WriteTask::cb ? EV_WRITE : 0); -} +namespace senf { +namespace scheduler { -///////////////////////////////cci.e/////////////////////////////////////// -#undef prefix_ + void restart(); + +namespace detail { + + class EventEventDispatcher + : public singleton + { + public: + using singleton::instance; + using singleton::alive; + + void add(EventEvent & event); + void remove(EventEvent & event); + + void prepareRun(); + + bool empty() const; + + private: + EventEventDispatcher(); + ~EventEventDispatcher(); + + typedef boost::intrusive::ilist< + EventEventListBase::value_traits, false > EventList; + + EventList events_; + + friend void senf::scheduler::restart(); + friend class singleton; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif // Local Variables: diff --git a/Scheduler/EventManager.cc b/Scheduler/EventManager.cc index aaf1622..3f00cde 100644 --- a/Scheduler/EventManager.cc +++ b/Scheduler/EventManager.cc @@ -43,11 +43,18 @@ prefix_ senf::scheduler::detail::EventManager::EventManager() .doc("List all scheduler events sorted by priority\n" "\n" "Columns:\n" - " TP event type: fd - file descriptor, tm - timer, si - UNIX signal\n" + " TP event type:\n" + " fd file descriptor\n" + " tm timer\n" + " si UNIX signal\n" + " ee event hook\n" " NAME descriptive event name\n" " ADDRESS address of event class instance\n" " RUNCNT number of times, the event was called\n" - " S state: R - runnable, W - Waiting, '-' - event disabled\n" + " S state:\n" + " R runnable\n" + " W waiting\n" + " - event disabled\n" " INFO further event specific information"); senf::console::sysdir().add("scheduler", consoleDir_()); diff --git a/Scheduler/FIFORunner.cc b/Scheduler/FIFORunner.cc index 8510c04..446859c 100644 --- a/Scheduler/FIFORunner.cc +++ b/Scheduler/FIFORunner.cc @@ -59,6 +59,9 @@ prefix_ senf::scheduler::detail::FIFORunner::FIFORunner() sigaddset(&mask, SIGURG); if (sigprocmask(SIG_UNBLOCK, &mask, 0) < 0) SENF_THROW_SYSTEM_EXCEPTION("sigprocmask()"); + + tasks_.push_back(highPriorityEnd_); + tasks_.push_back(normalPriorityEnd_); } prefix_ senf::scheduler::detail::FIFORunner::~FIFORunner() @@ -97,40 +100,66 @@ prefix_ void senf::scheduler::detail::FIFORunner::dequeue(TaskInfo * task) tasks_.erase(i); } -namespace { - struct NullTask - : public senf::scheduler::detail::FIFORunner::TaskInfo - { - NullTask() : senf::scheduler::detail::FIFORunner::TaskInfo ("") {} - virtual void v_run() {}; - virtual char const * v_type() const { return 0; } - virtual std::string v_info() const { return ""; } - }; +prefix_ void senf::scheduler::detail::FIFORunner::run() +{ + 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()"); + + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + timer.it_value.tv_sec = 0; + timer.it_value.tv_nsec = 0; + + try { + TaskList::iterator f (tasks_.begin()); + TaskList::iterator l (TaskList::current(highPriorityEnd_)); + run(f, l); + + f = l; ++f; + l = TaskList::current(normalPriorityEnd_); + run(f, l); + + f = l; ++f; + l = tasks_.end(); + run(f, l); + } + catch(...) { + timer_settime(watchdogId_, 0, &timer, 0); + throw; + } + + if (timer_settime(watchdogId_, 0, &timer, 0) < 0) + SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); } -prefix_ void senf::scheduler::detail::FIFORunner::run() + +prefix_ void senf::scheduler::detail::FIFORunner::run(TaskList::iterator f, TaskList::iterator l) { + if (f == l) + // We'll have problems inserting NullTask between f and l below, so just explicitly bail out + return; + // This algorithm is carefully adjusted to make it work even when arbitrary tasks are removed // from the queue // - Before we begin, we add a NullTask to the queue. The only purpose of this node is, to mark // the current end of the queue. The iterator to this node becomes the end iterator of the // range to process - // - We update the TaskInfo and move it to the end of the queue before calling the callback so + // - We update the TaskInfo and move it to the next queue Element before calling the callback so // we don't access the TaskInfo if it is removed while the callback is running // - We keep the next to-be-processed node in a class variable which is checked and updated // whenever a node is removed. + NullTask null; - 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; - tasks_.push_back(null); + tasks_.insert(l, null); TaskList::iterator end (TaskList::current(null)); - next_ = tasks_.begin(); + next_ = f; try { - if (timer_settime(watchdogId_, 0, &timer, 0) < 0) - SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); while (next_ != end) { TaskInfo & task (*next_); if (task.runnable_) { @@ -141,7 +170,7 @@ prefix_ void senf::scheduler::detail::FIFORunner::run() # endif TaskList::iterator i (next_); ++ next_; - tasks_.splice(tasks_.end(), tasks_, i); + tasks_.splice(l, tasks_, i); watchdogCount_ = 1; task.run(); } @@ -151,24 +180,25 @@ prefix_ void senf::scheduler::detail::FIFORunner::run() } 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(); + next_ = l; throw; } 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; - if (timer_settime(watchdogId_, 0, &timer, 0) < 0) - SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); - tasks_.erase(end); - next_ = tasks_.end(); + next_ = l; +} + +prefix_ senf::scheduler::detail::FIFORunner::TaskList::iterator +senf::scheduler::detail::FIFORunner::priorityEnd(TaskInfo::Priority p) +{ + switch (p) { + case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_LOW : + return tasks_.end(); + case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_NORMAL : + return TaskList::current(normalPriorityEnd_); + case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_HIGH : + return TaskList::current(highPriorityEnd_); + } + return tasks_.begin(); } prefix_ void senf::scheduler::detail::FIFORunner::watchdog(int, siginfo_t * si, void *) diff --git a/Scheduler/FIFORunner.cci b/Scheduler/FIFORunner.cci index 585bf6e..b2f6fe6 100644 --- a/Scheduler/FIFORunner.cci +++ b/Scheduler/FIFORunner.cci @@ -34,8 +34,12 @@ #define prefix_ inline ///////////////////////////////cci.p/////////////////////////////////////// -prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::TaskInfo(std::string const & name) - : Event(name), runnable_ (false) +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::FIFORunner::TaskInfo + +prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::TaskInfo(std::string const & name, + Priority priority) + : Event(name), runnable_ (false), priority_ (priority) {} prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::~TaskInfo() @@ -65,9 +69,40 @@ prefix_ bool senf::scheduler::detail::FIFORunner::TaskInfo::v_enabled() return TaskListBase::linked(); } +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::FIFORunner::NullTask + +prefix_ senf::scheduler::detail::FIFORunner::NullTask::NullTask() + : senf::scheduler::detail::FIFORunner::TaskInfo ("") +{} + +prefix_ senf::scheduler::detail::FIFORunner::NullTask::~NullTask() +{ + if (TaskListBase::linked()) + FIFORunner::instance().dequeue(this); +} + +prefix_ void senf::scheduler::detail::FIFORunner::NullTask::v_run() +{} + +prefix_ char const * senf::scheduler::detail::FIFORunner::NullTask::v_type() + const +{ + return 0; +} + +prefix_ std::string senf::scheduler::detail::FIFORunner::NullTask::v_info() + const +{ + return ""; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::FIFORunner + prefix_ void senf::scheduler::detail::FIFORunner::enqueue(TaskInfo * task) { - tasks_.push_back(*task); + tasks_.insert(priorityEnd(task->priority_), *task); #ifdef SENF_DEBUG std::stringstream ss; backtrace(ss, 32); diff --git a/Scheduler/FIFORunner.hh b/Scheduler/FIFORunner.hh index 40154d3..8803f75 100644 --- a/Scheduler/FIFORunner.hh +++ b/Scheduler/FIFORunner.hh @@ -61,7 +61,9 @@ namespace detail { public TaskListBase { public: - explicit TaskInfo(std::string const & name); + enum Priority { PRIORITY_LOW = 0, PRIORITY_NORMAL = 1, PRIORITY_HIGH = 2 }; + + explicit TaskInfo(std::string const & name, Priority priority=PRIORITY_NORMAL); virtual ~TaskInfo(); void run(); @@ -76,6 +78,7 @@ namespace detail { virtual bool v_enabled() const; bool runnable_; + Priority priority_; # ifdef SENF_DEBUG std::string backtrace_; # endif @@ -110,8 +113,24 @@ namespace detail { static void watchdog(int, siginfo_t *, void *); + TaskList::iterator priorityEnd(TaskInfo::Priority p); + void run(TaskList::iterator f, TaskList::iterator l); + + struct NullTask : public TaskInfo + { + NullTask(); + ~NullTask(); + virtual void v_run();; + virtual char const * v_type() const; + virtual std::string v_info() const; + }; + TaskList tasks_; TaskList::iterator next_; + + NullTask normalPriorityEnd_; + NullTask highPriorityEnd_; + timer_t watchdogId_; unsigned watchdogMs_; std::string runningName_; diff --git a/Scheduler/FdEvent.hh b/Scheduler/FdEvent.hh index 78409f4..6080d0d 100644 --- a/Scheduler/FdEvent.hh +++ b/Scheduler/FdEvent.hh @@ -75,9 +75,9 @@ namespace scheduler { handles are provided. The FdEvent class is an implementation of the RAII idiom: The event will be automatically - unregistered in the FdEvent destructor. The TimerEvent 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). + unregistered in the FdEvent destructor. The FdEvent 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 FdEvent : public detail::FIFORunner::TaskInfo, diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 7ba69ef..74761da 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -35,7 +35,6 @@ //#include "Scheduler.ih" // Custom includes -#include "SignalEvent.hh" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// @@ -61,19 +60,22 @@ prefix_ void senf::scheduler::process() detail::TimerDispatcher::instance().blockSignals(); detail::SignalDispatcher::instance().blockSignals(); detail::FileDispatcher::instance().prepareRun(); + detail::EventEventDispatcher::instance().prepareRun(); detail::FIFORunner::instance().run(); } } prefix_ void senf::scheduler::restart() { - detail::FdManager* fdm (&detail::FdManager::instance()); - detail::FIFORunner* ffr (&detail::FIFORunner::instance()); - detail::FdDispatcher* fdd (&detail::FdDispatcher::instance()); - detail::TimerDispatcher* tdd (&detail::TimerDispatcher::instance()); - detail::SignalDispatcher* sdd (&detail::SignalDispatcher::instance()); - detail::FileDispatcher* fld (&detail::FileDispatcher::instance()); - + detail::FdManager* fdm (&detail::FdManager::instance()); + detail::FIFORunner* ffr (&detail::FIFORunner::instance()); + detail::FdDispatcher* fdd (&detail::FdDispatcher::instance()); + detail::TimerDispatcher* tdd (&detail::TimerDispatcher::instance()); + detail::SignalDispatcher* sdd (&detail::SignalDispatcher::instance()); + detail::FileDispatcher* fld (&detail::FileDispatcher::instance()); + detail::EventEventDispatcher* eed (&detail::EventEventDispatcher::instance()); + + eed->~EventEventDispatcher(); fld->~FileDispatcher(); sdd->~SignalDispatcher(); tdd->~TimerDispatcher(); @@ -87,6 +89,7 @@ prefix_ void senf::scheduler::restart() new (tdd) detail::TimerDispatcher(); new (sdd) detail::SignalDispatcher(); new (fld) detail::FileDispatcher(); + new (eed) detail::EventEventDispatcher(); } prefix_ bool senf::scheduler::empty() @@ -94,7 +97,8 @@ prefix_ bool senf::scheduler::empty() return detail::FdDispatcher::instance().empty() && detail::TimerDispatcher::instance().empty() && detail::FileDispatcher::instance().empty() - && detail::SignalDispatcher::instance().empty(); + && detail::SignalDispatcher::instance().empty() + && detail::EventEventDispatcher::instance().empty(); } /////////////////////////////////////////////////////////////////////////// diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index af07c48..7cf6409 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -32,6 +32,7 @@ #include "FdEvent.hh" #include "TimerEvent.hh" #include "SignalEvent.hh" +#include "EventEvent.hh" //#include "scheduler.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -64,6 +65,7 @@ namespace senf { \li senf::scheduler::FdEvent for file descriptor events \li senf::scheduler::TimerEvent for single-shot deadline timer events \li senf::scheduler::SignalEvent for UNIX signal events + \li senf::scheduler::EventEvent for a special event hook These instance are owned and managed by the user of the scheduler \e not by the scheduler so the RAII concept can be used. diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index e270b06..a46aa18 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -212,6 +212,12 @@ namespace { senf::scheduler::terminate(); } + unsigned eventCount (0); + + void eventeventhandler() + { + ++ eventCount; + } } BOOST_AUTO_UNIT_TEST(testScheduler) @@ -236,6 +242,9 @@ BOOST_AUTO_UNIT_TEST(testScheduler) /////////////////////////////////////////////////////////////////////////// + senf::scheduler::EventEvent evev ("eventCounter", eventeventhandler, true, + senf::scheduler::EventEvent::PRIORITY_HIGH); + { senf::scheduler::FdEvent fde1 ("testFdEvent", boost::bind(&callback, sock, _1), sock, senf::scheduler::FdEvent::EV_READ); @@ -307,6 +316,8 @@ BOOST_AUTO_UNIT_TEST(testScheduler) BOOST_CHECK_NO_THROW( senf::scheduler::process() ); } + BOOST_CHECK_EQUAL( eventCount, 8u ); + /////////////////////////////////////////////////////////////////////////// close(sock); diff --git a/Socket/Mainpage.dox b/Socket/Mainpage.dox index 0a379c7..5485c7e 100644 --- a/Socket/Mainpage.dox +++ b/Socket/Mainpage.dox @@ -30,7 +30,9 @@ namespace senf { \autotoc \section socket_intro Introduction - + \seechapter \ref structure \n + \seechapter \ref usage + The socket library abstraction is based on several concepts: \li The basic visible interface is a \link handle_group handle object\endlink @@ -40,12 +42,10 @@ namespace senf { protocol_group protocol classes \endlink \li There is a family of auxilliary \ref addr_group to supplement the socket library - \see - \ref structure \n - \ref usage - \section socket_handle Socket Handles + \seechapter \ref handle_group \n + \seechapter \ref concrete_protocol_group The handle/body architecture provides automatic reference counted management of socket instances. This is the visible interface to the socket library. @@ -53,30 +53,26 @@ namespace senf { Each specific protocol is used primarily via a protocol specific handle (a typedef symbol). However, more generic kinds of handles can be defined for more generic functionality. - \see - \ref handle_group \n - \ref concrete_protocol_group \section socket_policy The Policy interface + \seechapter \ref policy_group The policy framework configures the exact features, a specific type of socket handle provides. This offers highly efficient access to the most important socket functions (like reading and writing). The policy interface however is a \e static, non-polymorphic interface. - \see - \ref policy_group \section socket_protocol The Protocol interface + \seechapter \ref protocol_group + The protocol interface provides further protocol dependent and (possibly) polymorphic access to further socket funcitonality. On the other hand, this type of interface is not as flexible, generic and fast as the policy interface. - \see - \ref protocol_group - \section socket_addr Auxilliary Addressing classes + \seechapter \ref addr_group To supplement the socket library, there are a multitude of addressing classes. These come in two basic groups: @@ -87,18 +83,14 @@ namespace senf { corresponding low-level address, the socket addresses are based on the corresponding \c sockaddr structures. - \see - \ref addr_group - \section socket_further Going further + \seechapter \ref extend \n + \seechapter \ref implementation The socket library is highly flexible and extensible. The implementation is not restricted to plain BSD sockets: Any type of read/write communication can be wrapped into the socket library (one Example is the TapSocketHandle which provides access to a Linux \c tap device). - \see - \ref extend \n - \ref implementation */ /** \page structure Overview of the Socket Library Structure