From: g0dil Date: Wed, 17 Sep 2008 08:41:16 +0000 (+0000) Subject: Scheduler: Implement new timer event API X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=db007c39287e3c666dd6b53edc8c3404617c7dd5;p=senf.git Scheduler: Implement new timer event API Scheduler: Move task 'name' argument to constructor Scheduler: Remove obsolete 'enabled_' members Scheduler: Remove obsolete SchedulerTimer class git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@907 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Server.cc b/Console/Server.cc index 3ef80ba..3148e76 100644 --- a/Console/Server.cc +++ b/Console/Server.cc @@ -224,8 +224,10 @@ prefix_ senf::console::Client::Client(Server & server, ClientHandle handle) : out_t(boost::ref(*this)), senf::log::IOStreamTarget(out_t::member), server_ (server), handle_ (handle), binding_ (handle, boost::bind(&Client::setNoninteractive,this), Scheduler::EV_READ, false), - timer_ (Scheduler::instance().eventTime() + ClockService::milliseconds(INTERACTIVE_TIMEOUT), - boost::bind(&Client::setInteractive, this), false), + timer_ ("senf::console::Client interactive timeout", + boost::bind(&Client::setInteractive, this), + Scheduler::instance().eventTime() + ClockService::milliseconds(INTERACTIVE_TIMEOUT), + false), name_ (server.name()), reader_ (), mode_ (server.mode()) { handle_.facet().nodelay(); diff --git a/Console/Server.hh b/Console/Server.hh index b7684d5..66426a0 100644 --- a/Console/Server.hh +++ b/Console/Server.hh @@ -36,7 +36,6 @@ #include "../Socket/ServerSocketHandle.hh" #include "../Scheduler/Scheduler.hh" #include "../Scheduler/Binding.hh" -#include "../Scheduler/Timer.hh" #include "../Scheduler/ReadHelper.hh" #include "Parse.hh" #include "Executor.hh" @@ -197,7 +196,7 @@ namespace console { Server & server_; ClientHandle handle_; SchedulerBinding binding_; - SchedulerTimer timer_; + scheduler::TimerEvent timer_; CommandParser parser_; Executor executor_; std::string name_; diff --git a/PPI/IdleEvent.cc b/PPI/IdleEvent.cc index 37077bb..4c98ad5 100644 --- a/PPI/IdleEvent.cc +++ b/PPI/IdleEvent.cc @@ -42,13 +42,12 @@ prefix_ void senf::ppi::IdleEvent::v_enable() { - id_ = Scheduler::instance().timeout(manager().now(), boost::bind(&IdleEvent::cb,this)); + timer_.timeout(manager().now()); } prefix_ void senf::ppi::IdleEvent::v_disable() { - Scheduler::instance().cancelTimeout(id_); - id_ = 0; + timer_.disable(); } prefix_ void senf::ppi::IdleEvent::cb() diff --git a/PPI/IdleEvent.cci b/PPI/IdleEvent.cci index 41ccf87..898c14b 100644 --- a/PPI/IdleEvent.cci +++ b/PPI/IdleEvent.cci @@ -32,7 +32,7 @@ // senf::ppi::IdleEvent prefix_ senf::ppi::IdleEvent::IdleEvent() - : id_(0) + : timer_ ("PPI idle event", boost::bind(&IdleEvent::cb,this)) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/PPI/IdleEvent.hh b/PPI/IdleEvent.hh index 6a70510..51656ea 100644 --- a/PPI/IdleEvent.hh +++ b/PPI/IdleEvent.hh @@ -56,7 +56,7 @@ namespace ppi { void cb(); - unsigned id_; + scheduler::TimerEvent timer_; }; }} diff --git a/PPI/IntervalTimer.cc b/PPI/IntervalTimer.cc index 507567e..f0dafd1 100644 --- a/PPI/IntervalTimer.cc +++ b/PPI/IntervalTimer.cc @@ -49,14 +49,13 @@ prefix_ void senf::ppi::IntervalTimer::v_enable() prefix_ void senf::ppi::IntervalTimer::v_disable() { - Scheduler::instance().cancelTimeout(id_); - id_ = 0; + timer_.disable(); } prefix_ void senf::ppi::IntervalTimer::schedule() { info_.expected = info_.intervalStart + ( interval_ * (info_.number+1) ) / eventsPerInterval_; - id_ = Scheduler::instance().timeout(info_.expected, boost::bind(&IntervalTimer::cb,this)); + timer_.timeout(info_.expected); } prefix_ void senf::ppi::IntervalTimer::cb() diff --git a/PPI/IntervalTimer.cci b/PPI/IntervalTimer.cci index f38316a..35c7ce2 100644 --- a/PPI/IntervalTimer.cci +++ b/PPI/IntervalTimer.cci @@ -33,7 +33,8 @@ prefix_ senf::ppi::IntervalTimer::IntervalTimer(ClockService::clock_type interval, unsigned eventsPerInterval) - : interval_ (interval), eventsPerInterval_ (eventsPerInterval) + : interval_ (interval), eventsPerInterval_ (eventsPerInterval), + timer_("PPI interval timer", boost::bind(&IntervalTimer::cb,this)) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/PPI/IntervalTimer.hh b/PPI/IntervalTimer.hh index 0e55aa5..1763f35 100644 --- a/PPI/IntervalTimer.hh +++ b/PPI/IntervalTimer.hh @@ -82,7 +82,7 @@ namespace ppi { ClockService::clock_type interval_; unsigned eventsPerInterval_; IntervalTimerEventInfo info_; - unsigned id_; + scheduler::TimerEvent timer_; }; }} diff --git a/PPI/SocketSink.test.cc b/PPI/SocketSink.test.cc index 0114565..d2b9435 100644 --- a/PPI/SocketSink.test.cc +++ b/PPI/SocketSink.test.cc @@ -84,8 +84,9 @@ BOOST_AUTO_UNIT_TEST(activeSocketSink) senf::UDPv4ClientSocketHandle inputSocket; inputSocket.bind(senf::INet4SocketAddress("localhost:44344")); - senf::Scheduler::instance().timeout( - senf::ClockService::now() + senf::ClockService::milliseconds(100), &timeout); + senf::scheduler::TimerEvent timer ( + "activeSocketSink test timer", &timeout, + senf::ClockService::now() + senf::ClockService::milliseconds(100)); source.submit(p); senf::ppi::run(); diff --git a/PPI/SocketSource.test.cc b/PPI/SocketSource.test.cc index d1f6263..bb1c59d 100644 --- a/PPI/SocketSource.test.cc +++ b/PPI/SocketSource.test.cc @@ -64,8 +64,9 @@ BOOST_AUTO_UNIT_TEST(socketSource) senf::UDPv4ClientSocketHandle outputSocket; outputSocket.writeto(senf::INet4SocketAddress("localhost:44344"),data); - senf::Scheduler::instance().timeout( - senf::ClockService::now() + senf::ClockService::milliseconds(100), &timeout); + senf::scheduler::TimerEvent timer ( + "socketSource test timer", &timeout, + senf::ClockService::now() + senf::ClockService::milliseconds(100)); senf::ppi::run(); BOOST_REQUIRE( ! sink.empty() ); diff --git a/Scheduler/FIFORunner.cc b/Scheduler/FIFORunner.cc index 7fbd9df..0e5d5be 100644 --- a/Scheduler/FIFORunner.cc +++ b/Scheduler/FIFORunner.cc @@ -101,6 +101,7 @@ namespace { struct NullTask : public senf::scheduler::FIFORunner::TaskInfo { + NullTask() : senf::scheduler::FIFORunner::TaskInfo ("") {} void run() {}; }; } diff --git a/Scheduler/FIFORunner.cci b/Scheduler/FIFORunner.cci index 6d2f52a..4bea7ba 100644 --- a/Scheduler/FIFORunner.cci +++ b/Scheduler/FIFORunner.cci @@ -34,8 +34,8 @@ #define prefix_ inline ///////////////////////////////cci.p/////////////////////////////////////// -prefix_ senf::scheduler::FIFORunner::TaskInfo::TaskInfo() - : runnable (false) +prefix_ senf::scheduler::FIFORunner::TaskInfo::TaskInfo(std::string const & name_) + : runnable (false), name (name_) {} prefix_ senf::scheduler::FIFORunner::TaskInfo::~TaskInfo() diff --git a/Scheduler/FIFORunner.hh b/Scheduler/FIFORunner.hh index 756f07f..2c04bc6 100644 --- a/Scheduler/FIFORunner.hh +++ b/Scheduler/FIFORunner.hh @@ -73,7 +73,7 @@ namespace scheduler { struct TaskInfo : public TaskListBase { - TaskInfo(); + explicit TaskInfo(std::string const & name_); virtual ~TaskInfo(); bool runnable; ///< Runnable flag diff --git a/Scheduler/FdDispatcher.cc b/Scheduler/FdDispatcher.cc index 4103b51..4d8007b 100644 --- a/Scheduler/FdDispatcher.cc +++ b/Scheduler/FdDispatcher.cc @@ -54,25 +54,19 @@ prefix_ bool senf::scheduler::FdDispatcher::add(std::string const & name, int fd FdMap::iterator i (fds_.find(fd)); if (i == fds_.end()) { - i = fds_.insert(std::make_pair(fd, FdEvent())).first; + i = fds_.insert(std::make_pair(fd, FdEvent(name))).first; runner_.enqueue(static_cast(&i->second)); runner_.enqueue(static_cast(&i->second)); runner_.enqueue(static_cast(&i->second)); } FdEvent & event (i->second); - if (events & EV_READ) { + if (events & EV_READ) event.FdEvent::ReadTask::cb = cb; - event.FdEvent::ReadTask::name = name; - } - if (events & EV_PRIO) { + if (events & EV_PRIO) event.FdEvent::PrioTask::cb = cb; - event.FdEvent::PrioTask::name = name; - } - if (events & EV_WRITE) { + if (events & EV_WRITE) event.FdEvent::WriteTask::cb = cb; - event.FdEvent::WriteTask::name = name; - } if (! manager_.set(fd, event.activeEvents(), &event)) { runner_.dequeue(static_cast(&i->second)); @@ -95,18 +89,12 @@ prefix_ void senf::scheduler::FdDispatcher::remove(int fd, int events) return; FdEvent & event (i->second); - if (events & EV_READ) { + if (events & EV_READ) event.FdEvent::ReadTask::cb = 0; - event.FdEvent::ReadTask::name.clear(); - } - if (events & EV_PRIO) { + if (events & EV_PRIO) event.FdEvent::PrioTask::cb = 0; - event.FdEvent::PrioTask::name.clear(); - } - if (events & EV_WRITE) { + if (events & EV_WRITE) event.FdEvent::WriteTask::cb = 0; - event.FdEvent::WriteTask::name.clear(); - } int activeEvents (event.activeEvents()); if (! activeEvents) { diff --git a/Scheduler/FdDispatcher.hh b/Scheduler/FdDispatcher.hh index affc61d..bfca398 100644 --- a/Scheduler/FdDispatcher.hh +++ b/Scheduler/FdDispatcher.hh @@ -97,6 +97,9 @@ namespace scheduler { typedef detail::FdTask<1, FdEvent> PrioTask; typedef detail::FdTask<2, FdEvent> WriteTask; + explicit FdEvent(std::string const & name) + : ReadTask (name), PrioTask (name), WriteTask (name) {} + virtual void signal(int events); int activeEvents() const; int events; diff --git a/Scheduler/FdDispatcher.ih b/Scheduler/FdDispatcher.ih index 42d3c85..b0c1c01 100644 --- a/Scheduler/FdDispatcher.ih +++ b/Scheduler/FdDispatcher.ih @@ -43,6 +43,9 @@ namespace detail { struct FdTask : public FIFORunner::TaskInfo { + explicit FdTask(std::string const & name) + : FIFORunner::TaskInfo (name) {} + typedef boost::function Callback; virtual void run(); Self & self(); diff --git a/Scheduler/FileDispatcher.cc b/Scheduler/FileDispatcher.cc index 780335c..6ada898 100644 --- a/Scheduler/FileDispatcher.cc +++ b/Scheduler/FileDispatcher.cc @@ -55,20 +55,16 @@ prefix_ void senf::scheduler::FileDispatcher::add(std::string const & name, int FileMap::iterator i (files_.find(fd)); if (i == files_.end()) { - i = files_.insert(std::make_pair(fd, FileEvent())).first; + i = files_.insert(std::make_pair(fd, FileEvent(name))).first; runner_.enqueue(static_cast(&i->second)); runner_.enqueue(static_cast(&i->second)); } FileEvent & event (i->second); - if (events & EV_READ) { + if (events & EV_READ) event.FileEvent::ReadTask::cb = cb; - event.FileEvent::ReadTask::name = name; - } - if (events & EV_WRITE) { + if (events & EV_WRITE) event.FileEvent::WriteTask::cb = cb; - event.FileEvent::WriteTask::name = name; - } manager_.timeout(0); } diff --git a/Scheduler/FileDispatcher.hh b/Scheduler/FileDispatcher.hh index 4bff54d..f81e3df 100644 --- a/Scheduler/FileDispatcher.hh +++ b/Scheduler/FileDispatcher.hh @@ -109,6 +109,9 @@ namespace scheduler { typedef detail::FdTask<0, FileEvent> ReadTask; typedef detail::FdTask<1, FileEvent> WriteTask; + explicit FileEvent(std::string const & name) + : ReadTask (name), WriteTask (name) {} + int activeEvents() const; int events; }; diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 1bfd963..1d0a107 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -44,12 +44,12 @@ prefix_ void senf::Scheduler::process() { terminate_ = false; while(! terminate_ && ! (fdDispatcher_.empty() && - timerDispatcher_.empty() && + scheduler::detail::TimerDispatcher::instance().empty() && fileDispatcher_.empty())) { scheduler::detail::SignalDispatcher::instance().unblockSignals(); - timerDispatcher_.unblockSignals(); + scheduler::detail::TimerDispatcher::instance().unblockSignals(); scheduler::FdManager::instance().processOnce(); - timerDispatcher_.blockSignals(); + scheduler::detail::TimerDispatcher::instance().blockSignals(); scheduler::detail::SignalDispatcher::instance().blockSignals(); fileDispatcher_.prepareRun(); scheduler::FIFORunner::instance().run(); @@ -61,7 +61,7 @@ prefix_ void senf::Scheduler::restart() scheduler::FdManager* fdm (&scheduler::FdManager::instance()); scheduler::FIFORunner* ffr (&scheduler::FIFORunner::instance()); scheduler::FdDispatcher* fdd (&fdDispatcher_); - scheduler::TimerDispatcher* td (&timerDispatcher_); + scheduler::detail::TimerDispatcher* td (&scheduler::detail::TimerDispatcher::instance()); scheduler::detail::SignalDispatcher* sd (&scheduler::detail::SignalDispatcher::instance()); scheduler::FileDispatcher* fld (&fileDispatcher_); @@ -75,7 +75,7 @@ prefix_ void senf::Scheduler::restart() new (fdm) scheduler::FdManager(); new (ffr) scheduler::FIFORunner(); new (fdd) scheduler::FdDispatcher(*fdm, *ffr); - new (td) scheduler::TimerDispatcher(*fdm, *ffr); + new (td) scheduler::detail::TimerDispatcher(); new (sd) scheduler::detail::SignalDispatcher(); new (fld) scheduler::FileDispatcher(*fdm, *ffr); } diff --git a/Scheduler/Scheduler.cci b/Scheduler/Scheduler.cci index 94cd693..27f463e 100644 --- a/Scheduler/Scheduler.cci +++ b/Scheduler/Scheduler.cci @@ -67,52 +67,6 @@ prefix_ int senf::retrieve_filehandle(int fd) return fd; } -prefix_ senf::Scheduler::timer_id senf::Scheduler::timeout(ClockService::clock_type timeout, - SimpleCallback const & cb) -{ - return timerDispatcher_.add("", timeout, cb); -} - -prefix_ senf::Scheduler::timer_id senf::Scheduler::timeout(std::string const & name, - ClockService::clock_type timeout, - SimpleCallback const & cb) -{ - return timerDispatcher_.add(name, timeout, cb); -} - -prefix_ void senf::Scheduler::cancelTimeout(timer_id id) -{ - timerDispatcher_.remove(id); -} - -prefix_ senf::ClockService::clock_type senf::Scheduler::timeoutEarly() - const -{ - SENF_LOG( (senf::log::IMPORTANT) - ("timeoutEarly() is deprecated and a no-op. It will be removed") ); - return 0; -} - -prefix_ void senf::Scheduler::timeoutEarly(ClockService::clock_type v) -{ - SENF_LOG( (senf::log::IMPORTANT) - ("timeoutEarly() is deprecated and a no-op. It will be removed") ); -} - -prefix_ senf::ClockService::clock_type senf::Scheduler::timeoutAdjust() - const -{ - SENF_LOG( (senf::log::IMPORTANT) - ("timeoutAdjust() is deprecated and a no-op. It will be removed") ); - return 0; -} - -prefix_ void senf::Scheduler::timeoutAdjust(ClockService::clock_type v) -{ - SENF_LOG( (senf::log::IMPORTANT) - ("timeoutAdjust() is deprecated and a no-op. It will be removed") ); -} - prefix_ void senf::Scheduler::terminate() { terminate_ = true; @@ -144,7 +98,6 @@ prefix_ unsigned senf::Scheduler::hangCount() prefix_ senf::Scheduler::Scheduler() : terminate_ (false), fdDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()), - timerDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()), fileDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()) {} diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index 7c4dbcb..c0c02bc 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -30,7 +30,7 @@ // Custom includes #include "../Utils/Logger/SenfLog.hh" #include "FdDispatcher.hh" -#include "TimerDispatcher.hh" +#include "TimerEvent.hh" #include "SignalEvent.hh" #include "FileDispatcher.hh" #include "../Utils/Logger/SenfLog.hh" @@ -189,9 +189,6 @@ namespace senf { /** \brief Callback type for signal events */ typedef boost::function SignalCallback; - /** \brief Timer id type */ - typedef scheduler::TimerDispatcher::timer_id timer_id; - /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///@{ @@ -253,35 +250,6 @@ namespace senf { ///\} - ///\name Timeouts - ///\{ - - timer_id timeout(std::string const & name, ClockService::clock_type timeout, - SimpleCallback const & cb); - ///< Add timeout event - /**< \returns timer id - \param[in] name descriptive name to identify the - callback. - \param[in] timeout timeout in nanoseconds - \param[in] cb callback to call after \a timeout - milliseconds */ - - timer_id timeout(ClockService::clock_type timeout, SimpleCallback const & cb); - ///< Add timeout event - /**< \see timeout() */ - - void cancelTimeout(timer_id id); ///< Cancel timeout \a id - -#ifndef DOXYGEN - ClockService::clock_type timeoutEarly() const; - void timeoutEarly(ClockService::clock_type v); - - ClockService::clock_type timeoutAdjust() const; - void timeoutAdjust(ClockService::clock_type v); -#endif - - ///\} - void process(); ///< Event handler main loop /**< This member must be called at some time to enter the event handler main loop. Only while this function is @@ -319,7 +287,6 @@ namespace senf { bool terminate_; scheduler::FdDispatcher fdDispatcher_; - scheduler::TimerDispatcher timerDispatcher_; scheduler::FileDispatcher fileDispatcher_; }; diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index 3bd241d..9efd343 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -247,28 +247,34 @@ BOOST_AUTO_UNIT_TEST(testScheduler) BOOST_REQUIRE_EQUAL( size, 4 ); buffer[size]=0; BOOST_CHECK_EQUAL( buffer, "READ" ); - - event = Scheduler::EV_NONE; - BOOST_CHECK_NO_THROW( Scheduler::instance().timeout( - ClockService::now()+ClockService::milliseconds(200),&timeout) ); - BOOST_CHECK_NO_THROW( Scheduler::instance().timeout( - ClockService::now()+ClockService::milliseconds(400),&timeout) ); - ClockService::clock_type t (ClockService::now()); - BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(200)) ); - BOOST_CHECK( timeoutCalled ); - BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (Scheduler::instance().eventTime()) ); - timeoutCalled = false; - BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(400)) ); - BOOST_CHECK( timeoutCalled ); - BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE ); - - BOOST_WARN_MESSAGE( false, "A 'Scheduler task hanging' error is expected to be signaled here." ); - BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(ClockService::now(), &blockingHandler) ); - BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_EQUAL( Scheduler::instance().hangCount(), 1u ); + + { + senf::scheduler::TimerEvent timer1 ("testTimer1", &timeout, + ClockService::now()+ClockService::milliseconds(200)); + senf::scheduler::TimerEvent timer2 ("testTimer2", &timeout, + ClockService::now()+ClockService::milliseconds(400)); + + event = Scheduler::EV_NONE; + ClockService::clock_type t (ClockService::now()); + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(200)) ); + BOOST_CHECK( timeoutCalled ); + BOOST_CHECK( ! timer1.enabled() ); + BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (Scheduler::instance().eventTime()) ); + timeoutCalled = false; + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(400)) ); + BOOST_CHECK( timeoutCalled ); + BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE ); + BOOST_CHECK( ! timer2.enabled() ); + + BOOST_WARN_MESSAGE( false, "A 'Scheduler task hanging' error is expected to be signaled here." ); + BOOST_CHECK_NO_THROW( timer1.action(&blockingHandler) ); + BOOST_CHECK_NO_THROW( timer1.timeout(ClockService::now()) ); + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_EQUAL( Scheduler::instance().hangCount(), 1u ); + } HandleWrapper handle(sock,"TheTag"); BOOST_CHECK_NO_THROW( Scheduler::instance().add(handle, @@ -290,20 +296,19 @@ BOOST_AUTO_UNIT_TEST(testScheduler) BOOST_CHECK_EQUAL( buffer, "OK" ); BOOST_CHECK_NO_THROW( Scheduler::instance().remove(handle) ); - unsigned tid (Scheduler::instance().timeout( - ClockService::now()+ClockService::milliseconds(400),&timeout)); { + senf::scheduler::TimerEvent timer ("testWatchdog", &timeout, + ClockService::now()+ClockService::milliseconds(400)); senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr); - t = ClockService::now(); + ClockService::clock_type t = ClockService::now(); ::kill(::getpid(), SIGUSR1); delay(100); BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) ); BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) ); + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); } - BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_NO_THROW( Scheduler::instance().cancelTimeout(tid) ); /////////////////////////////////////////////////////////////////////////// diff --git a/Scheduler/SignalEvent.cci b/Scheduler/SignalEvent.cci index 3a0407e..df29dd7 100644 --- a/Scheduler/SignalEvent.cci +++ b/Scheduler/SignalEvent.cci @@ -56,44 +56,39 @@ prefix_ bool senf::scheduler::detail::SignalDispatcher::empty() /////////////////////////////////////////////////////////////////////////// // senf::scheduler::SignalEvent -prefix_ senf::scheduler::SignalEvent::SignalEvent(int signal, Callback cb, +prefix_ senf::scheduler::SignalEvent::SignalEvent(int signal, Callback const & cb, bool initiallyEnabled) - : signal_ (signal), enabled_ (initiallyEnabled), cb_ (cb) + : FIFORunner::TaskInfo(signalName(signal)), signal_ (signal), cb_ (cb) { - name = signalName(signal); - if (enabled_) - senf::scheduler::detail::SignalDispatcher::instance().add(*this); + if (initiallyEnabled) + enable(); } prefix_ senf::scheduler::SignalEvent::~SignalEvent() { if (senf::scheduler::detail::SignalDispatcher::alive()) - senf::scheduler::detail::SignalDispatcher::instance().remove(*this); + disable(); } prefix_ void senf::scheduler::SignalEvent::disable() { - if (enabled_) { + if (detail::SignalSetBase::linked()) senf::scheduler::detail::SignalDispatcher::instance().remove(*this); - enabled_ = false; - } } prefix_ void senf::scheduler::SignalEvent::enable() { - if (! enabled_) { + if (! detail::SignalSetBase::linked()) senf::scheduler::detail::SignalDispatcher::instance().add(*this); - enabled_ = true; - } } prefix_ bool senf::scheduler::SignalEvent::enabled() const { - return enabled_; + return detail::SignalSetBase::linked(); } -prefix_ void senf::scheduler::SignalEvent::action(Callback cb) +prefix_ void senf::scheduler::SignalEvent::action(Callback const & cb) { cb_ = cb; } diff --git a/Scheduler/SignalEvent.hh b/Scheduler/SignalEvent.hh index a21c460..e5f2add 100644 --- a/Scheduler/SignalEvent.hh +++ b/Scheduler/SignalEvent.hh @@ -74,7 +74,7 @@ namespace scheduler { ///\name Structors and default members ///@{ - SignalEvent(int signal, Callback cb, bool initiallyEnabled=true); + SignalEvent(int signal, Callback const & cb, bool initiallyEnabled=true); ///< Register a signal event /**< Registers \a cb as callback for the UNIX signal \a signal. If \a initiallyEnabled is set \c false, the @@ -92,13 +92,12 @@ namespace scheduler { void disable(); ///< Enable signal event registration void enable(); ///< Disable the signal event registration bool enabled() const; ///< \c true, if event enabled, \c false otherwise - void action(Callback cb); ///< Change signal event callback + void action(Callback const & cb); ///< Change signal event callback private: virtual void run(); int signal_; - bool enabled_; Callback cb_; siginfo_t siginfo_; diff --git a/Scheduler/Timer.cci b/Scheduler/Timer.cci deleted file mode 100644 index dad761c..0000000 --- a/Scheduler/Timer.cci +++ /dev/null @@ -1,88 +0,0 @@ -// $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 Timer inline non-template implementation */ - -//#include "Timer.ih" - -// Custom includes - -#define prefix_ inline -///////////////////////////////cci.p/////////////////////////////////////// - -prefix_ senf::SchedulerTimer::SchedulerTimer(ClockService::clock_type timeout, - Scheduler::SimpleCallback const & cb, - bool enabled) - : timeout_ (timeout), cb_ (cb), - id_ (enabled ? Scheduler::instance().timeout(timeout_, cb_) : 0), - enabled_ (enabled) -{} - -prefix_ void senf::SchedulerTimer::enable() -{ - if (!enabled_) { - id_ = Scheduler::instance().timeout(timeout_, cb_); - enabled_ = true; - } -} - -prefix_ void senf::SchedulerTimer::disable() -{ - if (enabled_) { - Scheduler::instance().cancelTimeout(id_); - enabled_ = false; - } -} - -prefix_ bool senf::SchedulerTimer::enabled() -{ - return enabled_; -} - -prefix_ void senf::SchedulerTimer::update(ClockService::clock_type timeout) -{ - if (enabled_) - Scheduler::instance().cancelTimeout(id_); - timeout_ = timeout; - if (enabled_) - Scheduler::instance().timeout(timeout_, cb_); -} - -prefix_ senf::SchedulerTimer::~SchedulerTimer() -{ - disable(); -} - -///////////////////////////////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/Timer.hh b/Scheduler/Timer.hh deleted file mode 100644 index 93dbf43..0000000 --- a/Scheduler/Timer.hh +++ /dev/null @@ -1,108 +0,0 @@ -// $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 Timer public header */ - -#ifndef HH_Timer_ -#define HH_Timer_ 1 - -// Custom includes -#include "Scheduler.hh" - -//#include "Timer.mpp" -///////////////////////////////hh.p//////////////////////////////////////// - -namespace senf { - - /** \brief Manage scheduler timer - - This class will manage a single timer: The timer can be enabled, disabled and updated and - will automatically be removed, when this instance is destroyed. - - \code - class Foo - { - public: - Foo() : timer_ ( ClockServer::now() + ClockService::milliseconds(500), - senf::membind(&Foo::timer, this) ) {} - - void blarf() { timer_.disable(); } - - private: - void timer(); - - senf::SchedulerTimer timer_; - }; - \endcode - */ - class SchedulerTimer - : boost::noncopyable - { - public: - /////////////////////////////////////////////////////////////////////////// - ///\name Structors and default members - ///@{ - - SchedulerTimer(ClockService::clock_type timeout, Scheduler::SimpleCallback const & cb, - bool enabled=true); - ~SchedulerTimer(); - - ///@} - /////////////////////////////////////////////////////////////////////////// - - void enable(); ///< Enable timer - void disable(); ///< Disable timer - bool enabled(); ///< \c true, if timer is currently enabled - /**< An expired timer can still be in enabled state. */ - - void update(ClockService::clock_type timeout); ///< Change timeout time and enable timer - /**< If the timer is not enabled, you need to call enable() - for the timer to become effective. */ - - protected: - - private: - ClockService::clock_type timeout_; - Scheduler::SimpleCallback cb_; - unsigned id_; - bool enabled_; - }; - -} - -///////////////////////////////hh.e//////////////////////////////////////// -#include "Timer.cci" -//#include "Timer.ct" -//#include "Timer.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/TimerDispatcher.cci b/Scheduler/TimerDispatcher.cci deleted file mode 100644 index 6e8e9e6..0000000 --- a/Scheduler/TimerDispatcher.cci +++ /dev/null @@ -1,61 +0,0 @@ -// $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 TimerDispatcher inline non-template implementation */ - -//#include "TimerDispatcher.ih" - -// Custom includes -#include - -#define prefix_ inline -///////////////////////////////cci.p/////////////////////////////////////// - -prefix_ senf::scheduler::TimerDispatcher::TimerEvent::TimerEvent(timer_id id_, - Callback const & cb_, - TimerDispatcher & dispatcher_, - std::string const & n) - : id (id_), cb (cb_), dispatcher (dispatcher_) -{ - name = n; -} - -prefix_ bool senf::scheduler::TimerDispatcher::empty() - const -{ - return timers_.empty(); -} - -///////////////////////////////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/TimerDispatcher.hh b/Scheduler/TimerDispatcher.hh deleted file mode 100644 index 7b6f92a..0000000 --- a/Scheduler/TimerDispatcher.hh +++ /dev/null @@ -1,150 +0,0 @@ -// $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 TimerDispatcher public header */ - -#ifndef HH_TimerDispatcher_ -#define HH_TimerDispatcher_ 1 - -// Custom includes -#include -#include -#include -#include "ClockService.hh" -#include "FdManager.hh" -#include "FIFORunner.hh" -#include "../Utils/Logger/SenfLog.hh" - -//#include "TimerDispatcher.mpp" -///////////////////////////////hh.p//////////////////////////////////////// - -namespace senf { -namespace scheduler { - - /** \brief Scheduler dispatcher managing timers - - Timers are implemented using high-precision POSIX real-time timers. As such, the timer - granularity is given by clock_getres(CLOCK_MONOTONIC) which is 1ns on current linux kernels. - - \implementation TimerDispatcher manages a single POSIX timer which is always programmed to - expire when the next scheduled timer needs to fire. The timer sends a signal (SIGALRM is - used). The handler writes data into a pipe which is has been added to the FdManager. - */ - class TimerDispatcher - : public FdManager::Event - { - SENF_LOG_CLASS_AREA(); - - public: - /////////////////////////////////////////////////////////////////////////// - // Types - - typedef boost::function Callback; - typedef unsigned timer_id; - - /////////////////////////////////////////////////////////////////////////// - ///\name Structors and default members - ///@{ - - TimerDispatcher(FdManager & manager, FIFORunner & runner); - ~TimerDispatcher(); - - ///@} - /////////////////////////////////////////////////////////////////////////// - - timer_id add(std::string const & name, ClockService::clock_type timeout, - Callback const & cb); - ///< Add timer event - /**< This call adds a new timer expiring at the given point - in time. - \param[in] name descriptive name - \param[in] timeout point in time when the timer is to - expire - \param[in] cb callback - \returns a \c timer_id which can be used to remove the - timer. */ - void remove(timer_id id); ///< Remove timer - - void unblockSignals(); ///< Unblock internal signals - /**< Must be called before waiting for an event */ - void blockSignals(); ///< Block internal signals - /**< Must be called directly after the FdManager returns */ - - bool empty() const; ///< \c true, if no timer is registered. - - protected: - - private: - /// Internal: Timer event - struct TimerEvent - : public FIFORunner::TaskInfo - { - TimerEvent(timer_id id_, Callback const & cb_, TimerDispatcher & dispatcher_, - std::string const & name); - virtual void run(); - - timer_id id; - Callback cb; - TimerDispatcher & dispatcher; - }; - - virtual void signal(int events); - static void sigHandler(int signal, ::siginfo_t * siginfo, void *); - void reschedule(); - - FdManager & manager_; - FIFORunner & runner_; - - typedef std::multimap TimerMap; - typedef std::map TimerIdMap; - - TimerMap timers_; - TimerIdMap timerIdIndex_; - timer_id lastId_; - - int timerPipe_[2]; - sigset_t sigSet_; - bool blocked_; - timer_t timerId_; - - static unsigned useCount_; - }; - -}} - -///////////////////////////////hh.e//////////////////////////////////////// -#include "TimerDispatcher.cci" -//#include "TimerDispatcher.ct" -//#include "TimerDispatcher.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/TimerDispatcher.cc b/Scheduler/TimerEvent.cc similarity index 56% rename from Scheduler/TimerDispatcher.cc rename to Scheduler/TimerEvent.cc index 520500d..1a49800 100644 --- a/Scheduler/TimerDispatcher.cc +++ b/Scheduler/TimerEvent.cc @@ -23,37 +23,32 @@ /** \file \brief TimerDispatcher non-inline non-template implementation */ -#include "TimerDispatcher.hh" -//#include "TimerDispatcher.ih" +#include "TimerEvent.hh" +#include "TimerEvent.ih" // Custom includes -//#include "TimerDispatcher.mpp" +//#include "TimerEvent.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -unsigned senf::scheduler::TimerDispatcher::useCount_ (0); - -prefix_ senf::scheduler::TimerDispatcher::TimerDispatcher(FdManager & manager, - FIFORunner & runner) - : manager_ (manager), runner_ (runner), lastId_ (0), blocked_ (true) +prefix_ senf::scheduler::detail::TimerDispatcher::TimerDispatcher() + : blocked_ (true) { if (pipe(timerPipe_) < 0) SENF_THROW_SYSTEM_EXCEPTION("pipe()"); - manager_.set(timerPipe_[0], FdManager::EV_READ, this); + senf::scheduler::FdManager::instance().set(timerPipe_[0], FdManager::EV_READ, this); sigemptyset(&sigSet_); sigaddset(&sigSet_, SIGALRM); sigprocmask(SIG_BLOCK, &sigSet_, 0); - if (useCount_ == 0) { - struct sigaction act; - act.sa_sigaction = &sigHandler; - act.sa_mask = sigSet_; - act.sa_flags = SA_SIGINFO | SA_RESTART; - if (sigaction(SIGALRM, &act, 0) < 0) - SENF_THROW_SYSTEM_EXCEPTION("sigaction()"); - } + struct sigaction act; + act.sa_sigaction = &sigHandler; + act.sa_mask = sigSet_; + act.sa_flags = SA_SIGINFO | SA_RESTART; + if (sigaction(SIGALRM, &act, 0) < 0) + SENF_THROW_SYSTEM_EXCEPTION("sigaction()"); struct sigevent ev; ::memset(&ev, 0, sizeof(ev)); @@ -62,55 +57,43 @@ prefix_ senf::scheduler::TimerDispatcher::TimerDispatcher(FdManager & manager, ev.sigev_value.sival_ptr = this; if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0) SENF_THROW_SYSTEM_EXCEPTION("timer_create()"); - - ++ useCount_; } -prefix_ senf::scheduler::TimerDispatcher::~TimerDispatcher() +prefix_ senf::scheduler::detail::TimerDispatcher::~TimerDispatcher() { - -- useCount_; - - TimerMap::iterator i (timers_.begin()); - TimerMap::iterator const i_end (timers_.end()); + TimerSet::iterator i (timers_.begin()); + TimerSet::iterator const i_end (timers_.end()); for (; i != i_end; ++i) - runner_.dequeue(&(i->second)); + senf::scheduler::FIFORunner::instance().dequeue(&(*i)); timer_delete(timerId_); - if (useCount_ == 0) - ::signal(SIGALRM, SIG_IGN); + ::signal(SIGALRM, SIG_IGN); sigprocmask(SIG_UNBLOCK, &sigSet_, 0); - manager_.remove(timerPipe_[0]); + senf::scheduler::FdManager::instance().remove(timerPipe_[0]); close(timerPipe_[0]); close(timerPipe_[1]); } -prefix_ senf::scheduler::TimerDispatcher::timer_id -senf::scheduler::TimerDispatcher::add(std::string const & name, - ClockService::clock_type timeout, Callback const & cb) +void senf::scheduler::detail::TimerDispatcher::add(TimerEvent & event) { - while (timerIdIndex_.find(++lastId_) != timerIdIndex_.end()) ; - TimerMap::iterator i ( - timers_.insert(std::make_pair(timeout, TimerEvent(lastId_, cb, *this, name)))); - timerIdIndex_.insert(std::make_pair(lastId_, i)); - runner_.enqueue(&(i->second)); + TimerSet::iterator i (timers_.insert(event)); + senf::scheduler::FIFORunner::instance().enqueue(&(*i)); if (! blocked_) reschedule(); - return lastId_; } -prefix_ void senf::scheduler::TimerDispatcher::remove(timer_id id) +prefix_ void senf::scheduler::detail::TimerDispatcher::remove(TimerEvent & event) { - TimerIdMap::iterator i (timerIdIndex_.find(id)); - if (i == timerIdIndex_.end()) + TimerSet::iterator i (TimerSet::current(event)); + if (i == timers_.end()) return; - runner_.dequeue(&(i->second->second)); - timers_.erase(i->second); - timerIdIndex_.erase(i); + senf::scheduler::FIFORunner::instance().dequeue(&(*i)); + timers_.erase(i); if (! blocked_) reschedule(); } -prefix_ void senf::scheduler::TimerDispatcher::blockSignals() +prefix_ void senf::scheduler::detail::TimerDispatcher::blockSignals() { if (blocked_) return; @@ -118,7 +101,7 @@ prefix_ void senf::scheduler::TimerDispatcher::blockSignals() blocked_ = true; } -prefix_ void senf::scheduler::TimerDispatcher::unblockSignals() +prefix_ void senf::scheduler::detail::TimerDispatcher::unblockSignals() { if (! blocked_) return; @@ -127,21 +110,21 @@ prefix_ void senf::scheduler::TimerDispatcher::unblockSignals() blocked_ = false; } -prefix_ void senf::scheduler::TimerDispatcher::signal(int events) +prefix_ void senf::scheduler::detail::TimerDispatcher::signal(int events) { siginfo_t info; if (read(timerPipe_[0], &info, sizeof(info)) < int(sizeof(info))) return; - - TimerMap::iterator i (timers_.begin()); - TimerMap::iterator const i_end (timers_.end()); - ClockService::clock_type now (manager_.eventTime()); - for (; i != i_end && i->first <= now ; ++i) - i->second.runnable = true; + TimerSet::iterator i (timers_.begin()); + TimerSet::iterator const i_end (timers_.end()); + ClockService::clock_type now (senf::scheduler::FdManager::instance().eventTime()); + for (; i != i_end && i->timeout_ <= now ; ++i) + i->runnable = true; } -prefix_ void senf::scheduler::TimerDispatcher::sigHandler(int signal, ::siginfo_t * siginfo, - void *) +prefix_ void senf::scheduler::detail::TimerDispatcher::sigHandler(int signal, + ::siginfo_t * siginfo, + void *) { // The manpage says, si_signo is unused in linux so we set it here siginfo->si_signo = signal; @@ -152,7 +135,7 @@ prefix_ void senf::scheduler::TimerDispatcher::sigHandler(int signal, ::siginfo_ siginfo, sizeof(*siginfo)); } -prefix_ void senf::scheduler::TimerDispatcher::reschedule() +prefix_ void senf::scheduler::detail::TimerDispatcher::reschedule() { struct itimerspec timer; memset(&timer, 0, sizeof(timer)); @@ -164,7 +147,7 @@ prefix_ void senf::scheduler::TimerDispatcher::reschedule() timer.it_value.tv_nsec = 0; } else { - ClockService::clock_type next (timers_.begin()->first); + ClockService::clock_type next (timers_.begin()->timeout_); if (next <= 0) next = 1; timer.it_value.tv_sec = ClockService::in_seconds(next); @@ -178,21 +161,17 @@ prefix_ void senf::scheduler::TimerDispatcher::reschedule() } /////////////////////////////////////////////////////////////////////////// -// senf::scheduler::TimerDispatcher::TimerEvent +// senf::scheduler::detail::TimerDispatcher::TimerEvent -prefix_ void senf::scheduler::TimerDispatcher::TimerEvent::run() +prefix_ void senf::scheduler::TimerEvent::run() { - Callback savedCb (cb); - dispatcher.remove(id); - // The member is now running WITHOUT AN OBJECT ... that has been destroyed above !!!!!! On the - // other hand, if we do things the other way round, we have no idea, whether the callback might - // explicitly remove us and we have the same problem then ... - savedCb(); + disable(); + cb_(); } ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ -//#include "TimerDispatcher.mpp" +//#include "TimerEvent.mpp" // Local Variables: diff --git a/Scheduler/TimerEvent.cci b/Scheduler/TimerEvent.cci new file mode 100644 index 0000000..0dffcd9 --- /dev/null +++ b/Scheduler/TimerEvent.cci @@ -0,0 +1,108 @@ +// $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 TimerDispatcher inline non-template implementation */ + +#include "TimerEvent.ih" + +// Custom includes +#include + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::TimerEvent + +prefix_ senf::scheduler::TimerEvent::TimerEvent(std::string const & name, Callback const & cb, + ClockService::clock_type timeout, + bool initiallyEnabled) + : FIFORunner::TaskInfo (name), cb_ (cb), timeout_ (timeout) +{ + if (initiallyEnabled) + enable(); +} + +prefix_ senf::scheduler::TimerEvent::TimerEvent(std::string const & name, Callback const & cb) + : FIFORunner::TaskInfo (name), cb_ (cb), timeout_ (0) +{} + +prefix_ senf::scheduler::TimerEvent::~TimerEvent() +{ + if (senf::scheduler::detail::TimerDispatcher::alive()) + disable(); +} + +prefix_ void senf::scheduler::TimerEvent::enable() +{ + if (! detail::TimerSetBase::linked()) + senf::scheduler::detail::TimerDispatcher::instance().add(*this); +} + +prefix_ void senf::scheduler::TimerEvent::disable() +{ + if (detail::TimerSetBase::linked()) + senf::scheduler::detail::TimerDispatcher::instance().remove(*this); +} + +prefix_ bool senf::scheduler::TimerEvent::enabled() +{ + return detail::TimerSetBase::linked(); +} + +prefix_ void senf::scheduler::TimerEvent::action(Callback const & cb) +{ + cb_ = cb; +} + +prefix_ void senf::scheduler::TimerEvent::timeout(ClockService::clock_type timeout, + bool initiallyEnabled) +{ + disable(); + timeout_ = timeout; + if (initiallyEnabled) + enable(); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::TimerDispatcher + +prefix_ bool senf::scheduler::detail::TimerDispatcher::empty() + const +{ + return timers_.empty(); +} + +///////////////////////////////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/TimerEvent.hh b/Scheduler/TimerEvent.hh new file mode 100644 index 0000000..b0a4ae5 --- /dev/null +++ b/Scheduler/TimerEvent.hh @@ -0,0 +1,106 @@ +// $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 TimerDispatcher public header */ + +#ifndef HH_TimerDispatcher_ +#define HH_TimerDispatcher_ 1 + +// Custom includes +#include +#include "../boost/intrusive/iset_hook.hpp" +#include "ClockService.hh" +#include "FdManager.hh" +#include "FIFORunner.hh" +#include "../Utils/Logger/SenfLog.hh" + +//#include "TimerEvent.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace scheduler { + + namespace detail { + struct TimerSetTag; + typedef boost::intrusive::iset_base_hook TimerSetBase; + struct TimerSetCompare; + class TimerDispatcher; + } + + class TimerEvent + : public FIFORunner::TaskInfo, + public detail::TimerSetBase + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::function Callback; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + TimerEvent(std::string const & name, Callback const & cb, ClockService::clock_type timeout, + bool initiallyEnabled = true); + TimerEvent(std::string const & name, Callback const & cb); + ~TimerEvent(); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + void enable(); + void disable(); + bool enabled(); + + void action(Callback const & cb); + void timeout(ClockService::clock_type timeout, bool enable=true); + + private: + virtual void run(); + + Callback cb_; + ClockService::clock_type timeout_; + + friend class detail::TimerDispatcher; + friend class detail::TimerSetCompare; + }; + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "TimerEvent.cci" +//#include "TimerEvent.ct" +//#include "TimerEvent.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/TimerEvent.ih b/Scheduler/TimerEvent.ih new file mode 100644 index 0000000..8bae8d1 --- /dev/null +++ b/Scheduler/TimerEvent.ih @@ -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 +// +// 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 TimerDispatcher internal header */ + +#ifndef IH_TimerDispatcher_ +#define IH_TimerDispatcher_ 1 + +// Custom includes +#include "../boost/intrusive/iset.hpp" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { + + class Scheduler; + +namespace scheduler { +namespace detail { + + struct TimerSetCompare { + bool operator()(TimerEvent const & a, TimerEvent const & b) const + { return a.timeout_ < b.timeout_; } + }; + + class TimerDispatcher + : public FdManager::Event, + public singleton + { + SENF_LOG_CLASS_AREA(); + + typedef boost::intrusive::imultiset< TimerSetBase::value_traits, + TimerSetCompare, + false > TimerSet; + + public: + using singleton::instance; + using singleton::alive; + + void add(TimerEvent & event); + void remove(TimerEvent & event); + + void unblockSignals(); + void blockSignals(); + + bool empty() const; + + protected: + + private: + TimerDispatcher(); + ~TimerDispatcher(); + + virtual void signal(int events); + static void sigHandler(int signal, ::siginfo_t * siginfo, void *); + void reschedule(); + + TimerSet timers_; + + int timerPipe_[2]; + sigset_t sigSet_; + bool blocked_; + timer_t timerId_; + + friend class senf::Scheduler; + friend class singleton; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#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/TimerDispatcher.test.cc b/Scheduler/TimerEvent.test.cc similarity index 53% rename from Scheduler/TimerDispatcher.test.cc rename to Scheduler/TimerEvent.test.cc index 2795a8a..e7f777e 100644 --- a/Scheduler/TimerDispatcher.test.cc +++ b/Scheduler/TimerEvent.test.cc @@ -21,13 +21,13 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief TimerDispatcher.test unit tests */ + \brief TimerEvent.test unit tests */ -//#include "TimerDispatcher.test.hh" -//#include "TimerDispatcher.test.ih" +//#include "TimerEvent.test.hh" +//#include "TimerEvent.test.ih" // Custom includes -#include "TimerDispatcher.hh" +#include "TimerEvent.hh" #include "../Utils//auto_unit_test.hh" #include @@ -52,32 +52,35 @@ namespace { BOOST_AUTO_UNIT_TEST(timerDispatcher) { - senf::scheduler::TimerDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance()); senf::scheduler::FdManager::instance().timeout(1000); senf::ClockService::clock_type t (senf::ClockService::now()); - senf::scheduler::TimerDispatcher::timer_id id; - SENF_CHECK_NO_THROW( - id = dispatcher.add( "testTimer", t + senf::ClockService::milliseconds(500), &handler ) ); - SENF_CHECK_NO_THROW( dispatcher.unblockSignals() ); - SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); - SENF_CHECK_NO_THROW( dispatcher.blockSignals() ); - SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); - senf::ClockService::clock_type t2 (senf::ClockService::now()); - BOOST_CHECK( called ); - BOOST_CHECK_PREDICATE( is_close, (t2-t)(senf::ClockService::milliseconds(500)) ); - - SENF_CHECK_NO_THROW( dispatcher.remove(id) ); + { + senf::scheduler::TimerEvent timer ("testTimer", &handler, + t + senf::ClockService::milliseconds(500)); + SENF_CHECK_NO_THROW( timer.disable() ); + SENF_CHECK_NO_THROW( timer.enable() ); + BOOST_CHECK( timer.enabled() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().unblockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().blockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); + senf::ClockService::clock_type t2 (senf::ClockService::now()); + BOOST_CHECK( called ); + BOOST_CHECK( ! timer.enabled() ); + BOOST_CHECK_PREDICATE( is_close, (t2-t)(senf::ClockService::milliseconds(500)) ); - called=false; - t = senf::ClockService::now(); - SENF_CHECK_NO_THROW( dispatcher.add( "testTimer", t, &handler ) ); - SENF_CHECK_NO_THROW( dispatcher.unblockSignals() ); - SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); - SENF_CHECK_NO_THROW( dispatcher.blockSignals() ); - SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); - BOOST_CHECK_PREDICATE( is_close, (t) (senf::ClockService::now()) ); - BOOST_CHECK( called ); + called=false; + t = senf::ClockService::now(); + SENF_CHECK_NO_THROW( timer.timeout(t) ); + BOOST_CHECK( timer.enabled() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().unblockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().blockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); + BOOST_CHECK_PREDICATE( is_close, (t) (senf::ClockService::now()) ); + BOOST_CHECK( called ); + } } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index 19673af..89dbcec 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -563,6 +563,7 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout), stderr_(stderr), sigChld_(false), cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)), + timer_ ("DaemanWatcher watchdog", senf::membind(&DaemonWatcher::childOk, this)), coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) { @@ -594,9 +595,7 @@ prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id) childDied(); // does not return if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()"); - Scheduler::instance().timeout( - Scheduler::instance().eventTime() + ClockService::seconds(1), - senf::membind(&DaemonWatcher::childOk, this)); + timer_.timeout(Scheduler::instance().eventTime() + ClockService::seconds(1)); } } diff --git a/Utils/Daemon/Daemon.ih b/Utils/Daemon/Daemon.ih index 3dec5e2..795008a 100644 --- a/Utils/Daemon/Daemon.ih +++ b/Utils/Daemon/Daemon.ih @@ -95,6 +95,7 @@ namespace detail { bool sigChld_; scheduler::SignalEvent cldSignal_; + scheduler::TimerEvent timer_; Forwarder coutForwarder_; Forwarder cerrForwarder_; };