Scheduler: Make senf::scheduler::hangCount() reset the hang counter
g0dil [Wed, 18 Feb 2009 12:52:32 +0000 (12:52 +0000)]
Scheduler: Implement BlockSignals helper class

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1124 270642c3-0616-0410-b53a-bc976706d245

Scheduler/FIFORunner.cci
Scheduler/FIFORunner.hh
Scheduler/Scheduler.cc
Scheduler/Scheduler.cci
Scheduler/Scheduler.hh
Scheduler/Scheduler.test.cc

index d363dac..04afdcd 100644 (file)
@@ -124,9 +124,10 @@ prefix_ unsigned senf::scheduler::detail::FIFORunner::taskTimeout()
 }
 
 prefix_ unsigned senf::scheduler::detail::FIFORunner::hangCount()
-    const
 {
-    return hangCount_;
+    unsigned hc (hangCount_);
+    hangCount_ = 0;
+    return hc;
 }
 
 prefix_ senf::scheduler::detail::FIFORunner::iterator
index 27b626f..0573d9a 100644 (file)
@@ -103,7 +103,7 @@ namespace detail {
         void startWatchdog();
         void stopWatchdog();
 
-        unsigned hangCount() const;
+        unsigned hangCount();
 
         iterator begin() const;
         iterator end() const;
index 3203d20..f40bf69 100644 (file)
@@ -132,6 +132,33 @@ prefix_ senf::log::time_type senf::scheduler::LogTimeSource::operator()()
     return eventTime();
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::BlockSignals
+
+prefix_ senf::scheduler::BlockSignals::BlockSignals(bool initiallyBlocked)
+    : blocked_ (false)
+{
+    ::sigfillset(&allSigs_);
+    if (initiallyBlocked)
+        block();
+}
+
+prefix_ void senf::scheduler::BlockSignals::block()
+{
+    if (blocked_)
+        return;
+    ::sigprocmask(SIG_BLOCK, &allSigs_, &savedSigs_);
+    blocked_ = true;
+}
+
+prefix_ void senf::scheduler::BlockSignals::unblock()
+{
+    if (!blocked_)
+        return;
+    ::sigprocmask(SIG_SETMASK, &savedSigs_, 0);
+    blocked_ = false;
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index e85c4a5..b20de6e 100644 (file)
@@ -77,6 +77,20 @@ prefix_ bool senf::scheduler::usingHiresTimers()
         detail::TimerDispatcher::instance().timerSource()) == 0;
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::BlockSignals
+
+prefix_ senf::scheduler::BlockSignals::~BlockSignals()
+{
+    unblock();
+}
+
+prefix_ bool senf::scheduler::BlockSignals::blocked()
+    const
+{
+    return blocked_;
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
index 142f8eb..033c016 100644 (file)
@@ -28,6 +28,7 @@
 #define HH_SENF_Scheduler_Scheduler_ 1
 
 // Custom includes
+#include <boost/utility.hpp>
 #include "../Utils/Logger/SenfLog.hh"
 #include "FdEvent.hh"
 #include "TimerEvent.hh"
@@ -229,7 +230,10 @@ namespace scheduler {
     /** \brief Current task watchdog timeout */
     unsigned taskTimeout(); 
 
-    /** \brief Number of watchdog events */
+    /** \brief Number of watchdog events 
+
+        calling hangCount() will reset the counter to 0
+     */
     unsigned hangCount(); 
 
     /** \brief Switch to using hi resolution timers
@@ -291,6 +295,44 @@ namespace scheduler {
         senf::log::time_type operator()() const;
     };
 
+    /** \brief Temporarily block all signals
+
+        This class is used to temporarily block all signals in a critical section.
+        
+        \code
+        // Begin critical section
+        {
+            senf::scheduler::BlockSignals signalBlocker;
+
+            // critical code executed with all signals blocked
+        }
+        // End critical section
+        \endcode
+
+        You need to take care not to block since even the watchdog timer will be disabled while
+        executing within a critical section.
+     */
+    class BlockSignals
+        : boost::noncopyable
+    {
+    public:
+        BlockSignals(bool initiallyBlocked=true);
+                                        ///< Block signals until end of scope
+                                        /**< \param[in] initiallyBlocked set to \c false to not
+                                             automatically block signals initially */
+        ~BlockSignals();                ///< Release all signal blocks
+        
+        void block();                   ///< Block signals if not blocked
+        void unblock();                 ///< Unblock signals if blocked
+        bool blocked() const;           ///< \c true, if signals currently blocked, \c false
+                                        ///< otherwise
+
+    private:
+        bool blocked_;
+        sigset_t allSigs_;
+        sigset_t savedSigs_;
+    };
+
 }}
 
 ///////////////////////////////hh.e////////////////////////////////////////
index c23b6c9..b8c5b50 100644 (file)
@@ -45,8 +45,6 @@
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-using namespace senf;
-
 namespace {
 
     char const * SOCK_PATH = "/tmp/sched_test.sock";
@@ -186,16 +184,16 @@ namespace {
         callback(handle.fd_,event);
     }
 
-    bool is_close(ClockService::clock_type a, ClockService::clock_type b)
+    bool is_close(senf::ClockService::clock_type a, senf::ClockService::clock_type b)
     {
-        return (a<b ? b-a : a-b) < ClockService::milliseconds(100);
+        return (a<b ? b-a : a-b) < senf::ClockService::milliseconds(100);
     }
     
-    ClockService::clock_type sigtime (0);
+    senf::ClockService::clock_type sigtime (0);
 
     void sigusr(siginfo_t const &)
     {
-        sigtime = ClockService::now();
+        sigtime = senf::ClockService::now();
         senf::scheduler::terminate();
     }
 
@@ -221,7 +219,7 @@ namespace {
     }
 }
 
-BOOST_AUTO_UNIT_TEST(testScheduler)
+void schedulerTest()
 {
     int pid = start_server();
     BOOST_REQUIRE (pid);
@@ -277,50 +275,49 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
     
     {
         senf::scheduler::TimerEvent timer1 ("testTimer1", &timeout, 
-                                            ClockService::now()+ClockService::milliseconds(200));
+                                            senf::ClockService::now()+senf::ClockService::milliseconds(200));
         senf::scheduler::TimerEvent timer2 ("testTimer2", &timeout,
-                                            ClockService::now()+ClockService::milliseconds(400));
+                                            senf::ClockService::now()+senf::ClockService::milliseconds(400));
                                             
         event = senf::scheduler::FdEvent::EV_NONE;
-        ClockService::clock_type t (ClockService::now());
+        senf::ClockService::clock_type t (senf::ClockService::now());
         BOOST_CHECK_NO_THROW( senf::scheduler::process() );
-        BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(200)) );
+        BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()-t) (senf::ClockService::milliseconds(200)) );
         BOOST_CHECK( timeoutCalled );
         BOOST_CHECK( ! timer1.enabled() );
         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_NONE );
-        BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (senf::scheduler::eventTime()) );
+        BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()) (senf::scheduler::eventTime()) );
         timeoutCalled = false;
         BOOST_CHECK_NO_THROW( senf::scheduler::process() );
-        BOOST_CHECK_PREDICATE( is_close, (ClockService::now()-t) (ClockService::milliseconds(400)) );
+        BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()-t) (senf::ClockService::milliseconds(400)) );
         BOOST_CHECK( timeoutCalled );
         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_CHECK_NO_THROW( timer1.action(&blockingHandler) );
-        BOOST_CHECK_NO_THROW( timer1.timeout(ClockService::now()) );
+        BOOST_CHECK_NO_THROW( timer1.timeout(senf::ClockService::now()) );
         BOOST_CHECK_NO_THROW( senf::scheduler::process() );
         BOOST_CHECK_EQUAL( senf::scheduler::hangCount(), 1u );
     }
 
     {
         senf::scheduler::TimerEvent timer ("testWatchdog", &timeout,
-                                           ClockService::now()+ClockService::milliseconds(400));
+                                           senf::ClockService::now()+senf::ClockService::milliseconds(400));
         senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr);
 
-        ClockService::clock_type t = ClockService::now();
+        senf::ClockService::clock_type t = senf::ClockService::now();
         ::kill(::getpid(), SIGUSR1);
-        delay(100);
+        delay(200);
         BOOST_CHECK_NO_THROW( senf::scheduler::process() ); 
-        BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) );
-        BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) );
+        BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()) (t+senf::ClockService::milliseconds(200)) );
+        BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+senf::ClockService::milliseconds(200)) );
         BOOST_CHECK_NO_THROW( senf::scheduler::process() ); 
     } 
 
     BOOST_CHECK( eventCount >= 8u );
 
-    BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
-
     ///////////////////////////////////////////////////////////////////////////
 
     close(sock);
@@ -328,6 +325,56 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
     BOOST_CHECK (stop_server(pid));
 }
 
+BOOST_AUTO_UNIT_TEST(testSchedulerPollTimers)
+{
+    BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
+    schedulerTest();
+}
+
+BOOST_AUTO_UNIT_TEST(testSchedulerHiresTimers)
+{
+    senf::scheduler::hiresTimers();
+    BOOST_CHECK( senf::scheduler::usingHiresTimers() );
+    schedulerTest();
+    senf::scheduler::loresTimers();
+    BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
+}
+
+namespace {
+    
+    void sigme()
+    {
+        senf::scheduler::BlockSignals signalBlocker;
+        signalBlocker.block();
+        signalBlocker.unblock();
+        BOOST_CHECK( ! signalBlocker.blocked() );
+        signalBlocker.unblock();
+        signalBlocker.block();
+        BOOST_CHECK( signalBlocker.blocked() );
+        ::kill(::getpid(), SIGUSR1);
+        delay(200);
+    }
+
+}
+
+BOOST_AUTO_UNIT_TEST(blockSignals)
+{
+    senf::scheduler::TimerEvent signaler ("sigme", &sigme, senf::ClockService::now());
+    senf::scheduler::TimerEvent timer (
+        "testWatchdog", &timeout, senf::ClockService::now()+senf::ClockService::milliseconds(400));
+    senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr);
+    
+    senf::ClockService::clock_type t = senf::ClockService::now();
+    BOOST_CHECK_NO_THROW( senf::scheduler::process() ); 
+
+    BOOST_CHECK_PREDICATE( is_close, 
+                           (senf::ClockService::now()) 
+                           (t+senf::ClockService::milliseconds(200)) );
+    BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+senf::ClockService::milliseconds(200)) );
+
+    BOOST_CHECK_NO_THROW( senf::scheduler::process() ); 
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_