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()
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()
module_ = &module;
}
-prefix_ void senf::ppi::connector::Connector::init()
-{
- v_init();
-}
-
///////////////////////////////////////////////////////////////////////////
// senf::ppi::connector::PassiveConnector
#include "predecl.hh"
#include "detail/Callback.hh"
#include "Queueing.hh"
+#include "ModuleManager.hh"
//#include "Connectors.mpp"
///////////////////////////////hh.p////////////////////////////////////////
to the containing module)
*/
class Connector
- : boost::noncopyable
+ : ModuleManager::Initializable, boost::noncopyable
{
public:
Connector & peer() const; ///< Get peer connected to this connector
bool connected() const; ///< \c true, if connector connected, \c false otherwise
+ void disconnect(); ///< Disconnect connector from peer
+
protected:
Connector();
virtual ~Connector();
virtual std::type_info const & packetTypeID();
void setModule(module::Module & module);
- void init();
- virtual void v_init() = 0;
Connector * peer_;
module::Module * module_;
}
}
+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_
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
////////////////////////////////////////
// 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()
{}
#include <boost/ptr_container/ptr_vector.hpp>
#include "../Scheduler/ClockService.hh"
#include "predecl.hh"
+#include "ModuleManager.hh"
//#include "Module.mpp"
///////////////////////////////hh.p////////////////////////////////////////
\see \ref ppi_modules
*/
class Module
- : boost::noncopyable
+ : ModuleManager::Initializable, boost::noncopyable
{
public:
virtual ~Module();
private:
#endif
- void init();
virtual void v_init();
#ifndef DOXYGEN
// Custom includes
#include "../Scheduler/Scheduler.hh"
+#include "../Utils/membind.hh"
#include "Module.hh"
//#include "ModuleManager.mpp"
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
// 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////////////////////////////////////////
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_
// Custom includes
#include <vector>
+#include <deque>
#include "predecl.hh"
+#include "../Scheduler/Scheduler.hh"
//#include "ModuleManager.mpp"
///////////////////////////////hh.p////////////////////////////////////////
{
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
///@{
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<module::Module *> ModuleRegistry;
+ typedef std::deque<Initializable *> InitQueue;
#ifndef DOXYGEN
struct RunGuard;
bool running_;
bool terminate_;
+ InitQueue initQueue_;
+
+ scheduler::EventEvent initRunner_;
+
friend class module::Module;
+ friend class Initializable;
};
// Custom includes
#include "Connectors.hh"
+#include "Module.hh"
#include "ModuleManager.hh"
#define prefix_ inline
--- /dev/null
+// $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 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"
+
+\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:
--- /dev/null
+// $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 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_
+
+\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:
--- /dev/null
+// $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 EventEvent public header */
+
+#ifndef HH_EventEvent_
+#define HH_EventEvent_ 1
+
+// Custom includes
+#include <boost/function.hpp>
+#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<EventEventListTag> 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<void ()> 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
+
+\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:
// 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<EventEventDispatcher>
+ {
+ public:
+ using singleton<EventEventDispatcher>::instance;
+ using singleton<EventEventDispatcher>::alive;
+
+ void add(EventEvent & event);
+ void remove(EventEvent & event);
+
+ void prepareRun();
+
+ bool empty() const;
+
+ private:
+ EventEventDispatcher();
+ ~EventEventDispatcher();
+
+ typedef boost::intrusive::ilist<
+ EventEventListBase::value_traits<EventEvent>, false > EventList;
+
+ EventList events_;
+
+ friend void senf::scheduler::restart();
+ friend class singleton<EventEventDispatcher>;
+ };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
\f
// Local Variables:
.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_());
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()
tasks_.erase(i);
}
-namespace {
- struct NullTask
- : public senf::scheduler::detail::FIFORunner::TaskInfo
- {
- NullTask() : senf::scheduler::detail::FIFORunner::TaskInfo ("<null>") {}
- 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_) {
# endif
TaskList::iterator i (next_);
++ next_;
- tasks_.splice(tasks_.end(), tasks_, i);
+ tasks_.splice(l, tasks_, i);
watchdogCount_ = 1;
task.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 *)
#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()
return TaskListBase::linked();
}
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::FIFORunner::NullTask
+
+prefix_ senf::scheduler::detail::FIFORunner::NullTask::NullTask()
+ : senf::scheduler::detail::FIFORunner::TaskInfo ("<null>")
+{}
+
+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);
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();
virtual bool v_enabled() const;
bool runnable_;
+ Priority priority_;
# ifdef SENF_DEBUG
std::string backtrace_;
# endif
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_;
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,
//#include "Scheduler.ih"
// Custom includes
-#include "SignalEvent.hh"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
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();
new (tdd) detail::TimerDispatcher();
new (sdd) detail::SignalDispatcher();
new (fld) detail::FileDispatcher();
+ new (eed) detail::EventEventDispatcher();
}
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();
}
///////////////////////////////////////////////////////////////////////////
#include "FdEvent.hh"
#include "TimerEvent.hh"
#include "SignalEvent.hh"
+#include "EventEvent.hh"
//#include "scheduler.mpp"
///////////////////////////////hh.p////////////////////////////////////////
\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.
senf::scheduler::terminate();
}
+ unsigned eventCount (0);
+
+ void eventeventhandler()
+ {
+ ++ eventCount;
+ }
}
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);
BOOST_CHECK_NO_THROW( senf::scheduler::process() );
}
+ BOOST_CHECK_EQUAL( eventCount, 8u );
+
///////////////////////////////////////////////////////////////////////////
close(sock);
\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
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.
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:
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