From: g0dil Date: Wed, 28 Jan 2009 17:31:46 +0000 (+0000) Subject: Scheduler: Factor out TimerSource from TimerDispatcher and implement POSIXTimerSource X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=8057a9e389e33771aad9c78538f76d0e82ad7adb;p=senf.git Scheduler: Factor out TimerSource from TimerDispatcher and implement POSIXTimerSource git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1089 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/80211Bundle/RadiotapPacket.hh b/Packets/80211Bundle/RadiotapPacket.hh index 5ddec01..178556b 100644 --- a/Packets/80211Bundle/RadiotapPacket.hh +++ b/Packets/80211Bundle/RadiotapPacket.hh @@ -155,7 +155,7 @@ namespace senf OPTIONAL_FIELD ( flags, RadiotapPacketParser_Flags ); //setRunnable(); } -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; - // We can't do much on error anyway so we ignore errors here - if (siginfo->si_value.sival_ptr == 0) - return; - write(static_cast(siginfo->si_value.sival_ptr)->timerPipe_[1], - siginfo, sizeof(*siginfo)); -} - prefix_ void senf::scheduler::detail::TimerDispatcher::reschedule() { - struct itimerspec timer; - memset(&timer, 0, sizeof(timer)); - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - if (timers_.empty()) { - SENF_LOG( (senf::log::VERBOSE)("Timer disabled") ); - timer.it_value.tv_sec = 0; - timer.it_value.tv_nsec = 0; - } - else { - ClockService::clock_type next (timers_.begin()->timeout_); - if (next <= 0) - next = 1; - timer.it_value.tv_sec = ClockService::in_seconds(next); - timer.it_value.tv_nsec = ClockService::in_nanoseconds( - next - ClockService::seconds(timer.it_value.tv_sec)); - SENF_LOG( (senf::log::VERBOSE)("Next timeout scheduled @" << timer.it_value.tv_sec << "." - << std::setw(9) << std::setfill('0') << timer.it_value.tv_nsec) ); - } - if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0) - SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); + if (timers_.empty()) + source_->notimeout(); + else + source_->timeout(timers_.begin()->timeout_); } /////////////////////////////////////////////////////////////////////////// diff --git a/Scheduler/TimerEvent.cci b/Scheduler/TimerEvent.cci index 8527380..5fcf5ef 100644 --- a/Scheduler/TimerEvent.cci +++ b/Scheduler/TimerEvent.cci @@ -82,6 +82,16 @@ prefix_ void senf::scheduler::TimerEvent::timeout(ClockService::clock_type timeo /////////////////////////////////////////////////////////////////////////// // senf::scheduler::detail::TimerDispatcher +prefix_ void senf::scheduler::detail::TimerDispatcher::enable() +{ + source_->enable(); +} + +prefix_ void senf::scheduler::detail::TimerDispatcher::disable() +{ + source_->disable(); +} + prefix_ bool senf::scheduler::detail::TimerDispatcher::empty() const { diff --git a/Scheduler/TimerEvent.ih b/Scheduler/TimerEvent.ih index 1c5ea52..af9c104 100644 --- a/Scheduler/TimerEvent.ih +++ b/Scheduler/TimerEvent.ih @@ -27,7 +27,9 @@ #define IH_SENF_Scheduler_TimerEvent_ 1 // Custom includes +#include #include "../boost/intrusive/iset.hpp" +#include "TimerSource.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -44,8 +46,7 @@ namespace detail { }; class TimerDispatcher - : public detail::FdManager::Event, - public singleton + : public singleton { SENF_LOG_CLASS_AREA(); @@ -56,9 +57,12 @@ namespace detail { void add(TimerEvent & event); void remove(TimerEvent & event); - void unblockSignals(); - void blockSignals(); - + void enable(); + void disable(); + + void prepareRun(); + void reschedule(); + bool empty() const; protected: @@ -67,20 +71,13 @@ namespace detail { TimerDispatcher(); ~TimerDispatcher(); - virtual void signal(int events); - static void sigHandler(int signal, ::siginfo_t * siginfo, void *); - void reschedule(); - typedef boost::intrusive::imultiset< TimerSetBase::value_traits, TimerSetCompare, false > TimerSet; TimerSet timers_; - int timerPipe_[2]; - sigset_t sigSet_; - bool blocked_; - timer_t timerId_; + boost::scoped_ptr source_; friend void senf::scheduler::restart(); friend class singleton; diff --git a/Scheduler/TimerEvent.test.cc b/Scheduler/TimerEvent.test.cc index b626944..cbab9f6 100644 --- a/Scheduler/TimerEvent.test.cc +++ b/Scheduler/TimerEvent.test.cc @@ -61,10 +61,12 @@ BOOST_AUTO_UNIT_TEST(timerDispatcher) 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::detail::TimerDispatcher::instance().enable() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().reschedule() ); SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() ); - SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().blockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().prepareRun() ); SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().disable() ); senf::ClockService::clock_type t2 (senf::ClockService::now()); BOOST_CHECK( called ); BOOST_CHECK( ! timer.enabled() ); @@ -74,10 +76,12 @@ BOOST_AUTO_UNIT_TEST(timerDispatcher) 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::detail::TimerDispatcher::instance().enable() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().reschedule() ); SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() ); - SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().blockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().prepareRun() ); SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().disable() ); BOOST_CHECK_PREDICATE( is_close, (t) (senf::ClockService::now()) ); BOOST_CHECK( called ); } diff --git a/Scheduler/TimerSource.cc b/Scheduler/TimerSource.cc new file mode 100644 index 0000000..17d2de7 --- /dev/null +++ b/Scheduler/TimerSource.cc @@ -0,0 +1,162 @@ +// $Id$ +// +// Copyright (C) 2009 +// 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 TimerSource non-inline non-template implementation */ + +#include "TimerSource.hh" +//#include "TimerSource.ih" + +// Custom includes + +//#include "TimerSource.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::TimerSource + +prefix_ senf::scheduler::detail::TimerSource::~TimerSource() +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::POSIXTimerSource + +prefix_ senf::scheduler::detail::POSIXTimerSource::POSIXTimerSource() + : timeoutEnabled_ (false), timeout_ (0), signalEnabled_ (false) +{ + if (pipe(timerPipe_) < 0) + SENF_THROW_SYSTEM_EXCEPTION("pipe()"); + senf::scheduler::detail::FdManager::instance().set( + timerPipe_[0], detail::FdManager::EV_READ, this); + + sigemptyset(&sigSet_); + sigaddset(&sigSet_, SIGALRM); + sigprocmask(SIG_BLOCK, &sigSet_, 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 sigevent ev; + ::memset(&ev, 0, sizeof(ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGALRM; + ev.sigev_value.sival_ptr = this; + if (timer_create(CLOCK_MONOTONIC, &ev, &timerId_) < 0) + SENF_THROW_SYSTEM_EXCEPTION("timer_create()"); +} + +prefix_ senf::scheduler::detail::POSIXTimerSource::~POSIXTimerSource() +{ + timer_delete(timerId_); + ::signal(SIGALRM, SIG_IGN); + sigprocmask(SIG_UNBLOCK, &sigSet_, 0); + senf::scheduler::detail::FdManager::instance().remove(timerPipe_[0]); + close(timerPipe_[0]); + close(timerPipe_[1]); +} + +prefix_ void +senf::scheduler::detail::POSIXTimerSource::timeout(ClockService::clock_type timeout) +{ + if (! timeoutEnabled_ || timeout_ != timeout) { + timeout_ = timeout; + if (timeout_ <= 0) + timeout_ = 1; + timeoutEnabled_ = true; + reschedule(); + } +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::notimeout() +{ + if (timeoutEnabled_) { + timeoutEnabled_ = false; + reschedule(); + } +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::enable() +{ + if (! signalEnabled_) { + signalEnabled_ = true; + sigprocmask(SIG_UNBLOCK, &sigSet_, 0); + } +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::disable() +{ + if (signalEnabled_) { + signalEnabled_ = false; + sigprocmask(SIG_BLOCK, &sigSet_, 0); + } +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::sigHandler(int, + ::siginfo_t * siginfo, + void *) +{ + if (siginfo->si_value.sival_ptr == 0) + return; + static char data = '\xD0'; + write(static_cast(siginfo->si_value.sival_ptr)->timerPipe_[1], + &data, sizeof(data)); +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::signal(int events) +{ + char data; + read(timerPipe_[0], &data, sizeof(data)); + timeoutEnabled_ = false; +} + +prefix_ void senf::scheduler::detail::POSIXTimerSource::reschedule() +{ + struct itimerspec timer; + memset(&timer, 0, sizeof(timer)); + if (timeoutEnabled_) { + timer.it_value.tv_sec = ClockService::in_seconds(timeout_); + timer.it_value.tv_nsec = ClockService::in_nanoseconds( + timeout_ - ClockService::seconds(timer.it_value.tv_sec)); + } + if (timer_settime(timerId_, TIMER_ABSTIME, &timer, 0)<0) + SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "TimerSource.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/TimerSource.cci b/Scheduler/TimerSource.cci new file mode 100644 index 0000000..de09775 --- /dev/null +++ b/Scheduler/TimerSource.cci @@ -0,0 +1,51 @@ +// $Id$ +// +// Copyright (C) 2009 +// 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 TimerSource inline non-template implementation */ + +//#include "TimerSource.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::scheduler::detail::TimerSource + +prefix_ senf::scheduler::detail::TimerSource::TimerSource() +{} + +///////////////////////////////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/TimerSource.hh b/Scheduler/TimerSource.hh new file mode 100644 index 0000000..f17c6fc --- /dev/null +++ b/Scheduler/TimerSource.hh @@ -0,0 +1,117 @@ +// $Id$ +// +// Copyright (C) 2009 +// 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 TimerSource public header */ + +#ifndef HH_SENF_Scheduler_TimerSource_ +#define HH_SENF_Scheduler_TimerSource_ 1 + +// Custom includes +#include +#include +#include "ClockService.hh" +#include "FdManager.hh" + +//#include "TimerSource.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace scheduler { +namespace detail { + + class TimerSource + : boost::noncopyable + { + public: + virtual ~TimerSource(); + + virtual void timeout(ClockService::clock_type timeout) = 0; + virtual void notimeout() = 0; + + virtual void enable() = 0; + virtual void disable() = 0; + + protected: + TimerSource(); + }; + + class POSIXTimerSource + : public detail::FdManager::Event, public TimerSource + { + public: + POSIXTimerSource(); + ~POSIXTimerSource(); + + virtual void timeout(ClockService::clock_type timeout); + virtual void notimeout(); + + virtual void enable(); + virtual void disable(); + + private: + static void sigHandler(int signal, ::siginfo_t * siginfo, void *); + virtual void signal(int events); + void reschedule(); + + bool timeoutEnabled_; + ClockService::clock_type timeout_; + int timerPipe_[2]; + sigset_t sigSet_; + bool signalEnabled_; + timer_t timerId_; + }; + + class PollTimerSource + : public TimerSource + { + public: + virtual void timeout(ClockService::clock_type timeout); + virtual void disableTimeout(); + }; + + class TimerFDTimerSource + : public TimerSource + { + public: + virtual void timeout(ClockService::clock_type timeout); + virtual void disableTimeout(); + }; + +}}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "TimerSource.cci" +//#include "TimerSource.ct" +//#include "TimerSource.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: