From b6cff3b950c38b0a2fceaca6b49e79ab09c8bae8 Mon Sep 17 00:00:00 2001
From: g0dil <g0dil@wiback.org>
Date: Thu, 19 Feb 2009 12:13:32 +0000
Subject: [PATCH] Scheduler: Implement TimerFDTimerSource

---
 Scheduler/Scheduler.cci     | 14 ++++++--
 Scheduler/Scheduler.test.cc | 17 ++++++++-
 Scheduler/TimerSource.cc    | 69 +++++++++++++++++++++++++++++++++++++
 Scheduler/TimerSource.hh    | 24 +++++++++++++
 config.hh                   |  5 +++
 5 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/Scheduler/Scheduler.cci b/Scheduler/Scheduler.cci
index b20de6ea..acce9dbc 100644
--- a/Scheduler/Scheduler.cci
+++ b/Scheduler/Scheduler.cci
@@ -56,8 +56,14 @@ prefix_ unsigned senf::scheduler::hangCount()
 
 prefix_ void senf::scheduler::hiresTimers()
 {
-    detail::TimerDispatcher::instance().timerSource(
-        std::auto_ptr<detail::TimerSource>(new detail::POSIXTimerSource()));
+#ifdef HAVE_TIMERFD
+    if (haveScalableHiresTimers())
+        detail::TimerDispatcher::instance().timerSource(
+            std::auto_ptr<detail::TimerSource>(new detail::TimerFDTimerSource()));
+    else
+#endif
+        detail::TimerDispatcher::instance().timerSource(
+            std::auto_ptr<detail::TimerSource>(new detail::POSIXTimerSource()));
 }
 
 prefix_ void senf::scheduler::loresTimers()
@@ -68,7 +74,11 @@ prefix_ void senf::scheduler::loresTimers()
 
 prefix_ bool senf::scheduler::haveScalableHiresTimers()
 {
+#ifndef HAVE_TIMERFD
     return false;
+#else
+    return true;
+#endif
 }
 
 prefix_ bool senf::scheduler::usingHiresTimers()
diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc
index 2254cdbb..75bc76a6 100644
--- a/Scheduler/Scheduler.test.cc
+++ b/Scheduler/Scheduler.test.cc
@@ -294,7 +294,7 @@ void schedulerTest()
         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_NONE );
         BOOST_CHECK( ! timer2.enabled() );
 
-        BOOST_WARN_MESSAGE( false, "A 'Scheduler task hanging' error is expected to be signaled here." );
+        BOOST_MESSAGE( "A 'Scheduler task hanging' error is expected to be signaled here." );
         SENF_CHECK_NO_THROW( timer1.action(&blockingHandler) );
         SENF_CHECK_NO_THROW( timer1.timeout(senf::ClockService::now()) );
         SENF_CHECK_NO_THROW( senf::scheduler::process() );
@@ -333,6 +333,10 @@ BOOST_AUTO_UNIT_TEST(testSchedulerPollTimers)
 
 BOOST_AUTO_UNIT_TEST(testSchedulerHiresTimers)
 {
+    if (senf::scheduler::haveScalableHiresTimers())
+        BOOST_MESSAGE( "Using timerfd() hires timers" );
+    else
+        BOOST_MESSAGE( "Using POSIX hires timers");
     senf::scheduler::hiresTimers();
     BOOST_CHECK( senf::scheduler::usingHiresTimers() );
     schedulerTest();
@@ -340,6 +344,17 @@ BOOST_AUTO_UNIT_TEST(testSchedulerHiresTimers)
     BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
 }
 
+BOOST_AUTO_UNIT_TEST(testSchedulerPOSIXTimers)
+{
+    if (senf::scheduler::haveScalableHiresTimers()) {
+        senf::scheduler::detail::TimerDispatcher::instance().timerSource(
+            std::auto_ptr<senf::scheduler::detail::TimerSource>(
+                new senf::scheduler::detail::POSIXTimerSource()));
+        schedulerTest();
+        senf::scheduler::loresTimers();
+    }
+}
+
 namespace {
     
     void sigme()
diff --git a/Scheduler/TimerSource.cc b/Scheduler/TimerSource.cc
index 84048b09..ac1baa38 100644
--- a/Scheduler/TimerSource.cc
+++ b/Scheduler/TimerSource.cc
@@ -28,6 +28,9 @@
 
 // Custom includes
 #include "FdEvent.hh"
+#ifdef HAVE_TIMERFD
+#include <sys/timerfd.h>
+#endif
 
 //#include "TimerSource.mpp"
 #define prefix_
@@ -168,6 +171,72 @@ prefix_ void senf::scheduler::detail::PollTimerSource::enable()
 prefix_ void senf::scheduler::detail::PollTimerSource::disable()
 {}
 
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::TimerFDTimerSource
+
+#ifdef HAVE_TIMERFD
+prefix_ senf::scheduler::detail::TimerFDTimerSource::TimerFDTimerSource()
+    : timerfd_ (-1), timeoutEnabled_ (false), timeout_ (0)
+{
+    timerfd_ = timerfd_create(CLOCK_MONOTONIC, 0);
+    if (timerfd_ < 0)
+        SENF_THROW_SYSTEM_EXCEPTION("timerfd_create()");
+    senf::scheduler::detail::FdManager::instance().set(
+        timerfd_, detail::FdManager::EV_READ, this);
+}
+
+prefix_ senf::scheduler::detail::TimerFDTimerSource::~TimerFDTimerSource()
+{
+    senf::scheduler::detail::FdManager::instance().remove(timerfd_);
+    close(timerfd_);
+}
+
+prefix_ void
+senf::scheduler::detail::TimerFDTimerSource::timeout(ClockService::clock_type timeout)
+{
+    if (!timeoutEnabled_ || timeout_ != timeout) {
+        timeout_ = timeout;
+        if (timeout_ <= 0)
+            timeout_ = 1;
+        timeoutEnabled_ = true;
+        reschedule();
+    }
+}
+
+prefix_ void senf::scheduler::detail::TimerFDTimerSource::notimeout()
+{
+    if (timeoutEnabled_) {
+        timeoutEnabled_ = false;
+        reschedule();
+    }
+}
+
+prefix_ void senf::scheduler::detail::TimerFDTimerSource::enable()
+{}
+
+prefix_ void senf::scheduler::detail::TimerFDTimerSource::disable()
+{}
+
+prefix_ void senf::scheduler::detail::TimerFDTimerSource::signal(int events)
+{
+    uint64_t expirations (0);
+    read(timerfd_, &expirations, sizeof(expirations));
+}
+
+prefix_ void senf::scheduler::detail::TimerFDTimerSource::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 (timerfd_settime(timerfd_, TIMER_ABSTIME, &timer, 0)<0)
+        SENF_THROW_SYSTEM_EXCEPTION("timerfd_settime()");
+}
+#endif
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "TimerSource.mpp"
diff --git a/Scheduler/TimerSource.hh b/Scheduler/TimerSource.hh
index 4ae57193..d3afcadf 100644
--- a/Scheduler/TimerSource.hh
+++ b/Scheduler/TimerSource.hh
@@ -92,6 +92,30 @@ namespace detail {
         virtual void disable();
     };
 
+#ifdef HAVE_TIMERFD
+    class TimerFDTimerSource
+        : public detail::FdManager::Event, public TimerSource
+    {
+    public:
+        TimerFDTimerSource();
+        ~TimerFDTimerSource();
+
+        virtual void timeout(ClockService::clock_type timeout);
+        virtual void notimeout();
+
+        virtual void enable();
+        virtual void disable();
+
+    private:
+        virtual void signal(int events);
+        void reschedule();
+
+        int timerfd_;
+        bool timeoutEnabled_;
+        ClockService::clock_type timeout_;
+    };
+#endif
+
 }}}
 
 ///////////////////////////////hh.e////////////////////////////////////////
diff --git a/config.hh b/config.hh
index 12e24b5d..bf13b1e3 100644
--- a/config.hh
+++ b/config.hh
@@ -28,6 +28,7 @@
 # 
 # // Custom includes
 # include <boost/cstdint.hpp>
+# include <limits.h>
 # 
 # ///////////////////////////////hh.p////////////////////////////////////////
 
@@ -96,6 +97,10 @@ namespace config {
 # ifndef PHOENIX_LIMIT
 #     define PHOENIX_LIMIT 6
 # endif
+#
+# if __GLIBC__>=2 && __GLIBC_MINOR__>=8
+#     define HAVE_TIMERFD 1
+# endif
 # 
 # ///////////////////////////////hh.e////////////////////////////////////////
 # endif
-- 
GitLab