Fix Build-Depends in debian/control
[senf.git] / Scheduler / Scheduler.hh
index af07c48..9f3d3cd 100644 (file)
     \brief Scheduler public header
  */
 
-#ifndef HH_Scheduler_
-#define HH_Scheduler_ 1
+#ifndef HH_SENF_Scheduler_Scheduler_
+#define HH_SENF_Scheduler_Scheduler_ 1
 
 // Custom includes
+#include <boost/utility.hpp>
 #include "../Utils/Logger/SenfLog.hh"
 #include "FdEvent.hh"
 #include "TimerEvent.hh"
 #include "SignalEvent.hh"
+#include "EventHook.hh"
 
 //#include "scheduler.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -64,6 +66,7 @@ namespace senf {
     \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::EventHook 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.
@@ -193,6 +196,31 @@ namespace senf {
     href="http://www.boost.org/doc/libs/1_36_0/libs/ptr_container/doc/ptr_container.html">Boost.PointerContainer</a>
     for the pointer container library reference.
 
+
+    \section sched_signals Signals and the Watchdog
+
+    To secure against blocking callbacks, the %scheduler implementation includes a watchdog
+    timer. This timer will produce a warning message on the standard error stream when a single
+    callback is executing for more than the watchdog timeout value. Since the scheduler
+    implementation is completely single threaded, we cannot terminate the callback but at least we
+    can produce an informative message and optionally the program can be aborted.
+
+    The watchdog is controlled using the watchdogTimeout(), watchdogEvents() and watchdogAbort().
+    functions. 
+
+    The watchdog is implemented using a free running interval timer. The watchdog signal (\c SIGURG)
+    must \e not be blocked. If signals need to be blocked for some reason, those regions will not be
+    checked by the watchdog. If a callback blocks, the watchdog has no chance to interrupt the
+    process.
+
+    \warning Since the watchdog is free running for performance reasons, every callback must expect
+        signals to happen. Signals \e will certainly happen since the watchdog signal is generated
+        periodically (which does not necessarily generate a watchdog event ...)
+
+    Additional signals (\c SIGALRM) may occur when using using hires timers on kernel/glibc
+    combinations which do not support timerfd(). On such systems, hires timers are implemented using
+    POSIX timers which generate a considerable number of additional signals.
+
     \todo Fix the file support to use threads (?) fork (?) and a pipe so it works reliably even
         over e.g. NFS.
   */
@@ -205,7 +233,10 @@ namespace scheduler {
         \li a callback calls terminate()
         \li the run queue becomes empty. 
      */    
-    void process();                     
+    void process();
+
+    /** \brief \c true, if scheduler is running, \c false otherwise */
+    bool running();
 
     /** \brief Called by callbacks to terminate the main loop
 
@@ -221,14 +252,69 @@ namespace scheduler {
      */
     ClockService::clock_type eventTime(); 
 
-    /** \brief Set task watchdog timeout */
-    void taskTimeout(unsigned ms); 
+    /** \brief Return (approximate) current time
+
+        This call will return the current time as far as it is already known to the scheduler. If
+        the scheduler is running, this will return eventTime(), otherwise it will return
+        ClockService::now(). While the scheduler is running, this will reduce the number of system
+        calls.
+     */
+    ClockService::clock_type now();
+
+    /** \brief Set watchdog timeout to \a ms milliseconds.
+        
+        Setting the watchdog timeout to 0 will disable the watchdog.
+     */
+    void watchdogTimeout(unsigned ms); 
+
+    /** \brief Current watchdog timeout in milliseconds */
+    unsigned watchdogTimeout(); 
+
+    /** \brief Number of watchdog events 
+
+        calling watchtogEvents() will reset the counter to 0
+     */
+    unsigned watchdogEvents(); 
+
+    /** \brief Enable/disable abort on watchdog event.
+        
+        Calling watchdogAbort(\c true) will enable aborting the program execution on a watchdog
+        event.
+     */
+    void watchdogAbort(bool flag);
+
+    /** \brief Get current watchdog abort on event status */
+    bool watchdogAbort();
+
+    /** \brief Switch to using hi resolution timers
+        
+        By default, timers are implemented directly using epoll. This however restricts the timer
+        resolution to that of the kernel HZ value.
+
+        High resolution timers are implemented either using POSIX timers or, when available, using
+        the Linux special \c timerfd() syscall.
+
+        POSIX timers are delivered using signals. A high timer load this increases the signal load
+        considerably. \c timerfd()'s are delivered on a file descriptor and thus don't have such a
+        scalability issue.
+
+        \warning The timer source must not be switched from a scheduler callback
+     */
+    void hiresTimers();
+
+    /** \brief Switch back to using epoll for timing
+        \see hiresTimers()
+     */
+    void loresTimers();
 
-    /** \brief Current task watchdog timeout */
-    unsigned taskTimeout(); 
+    /** \brief return \c true, if \c timerfd() timing is available, \c false otherwise
+        \see hiresTimers()
+     */
+    bool haveScalableHiresTimers();
 
-    /** \brief Number of watchdog events */
-    unsigned hangCount(); 
+    /** \brief Return \c true, if using hires times, \c false otherwise
+        \see hiresTimers() */
+    bool usingHiresTimers();
 
     /** \brief Restart scheduler
         
@@ -238,7 +324,7 @@ namespace scheduler {
      */
     void restart(); 
 
-    /** \brief Return \c true, if any event is registered, \c false otherwise. */
+    /** \brief Return \c true, if no event is registered, \c false otherwise. */
     bool empty();
 
     /** \brief %scheduler specific time source for Utils/Logger framework
@@ -259,6 +345,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////////////////////////////////////////