Packets: Add StringParser ostream operation
[senf.git] / Scheduler / Scheduler.hh
index fdd5f59..62a687c 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"
@@ -195,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.
   */
@@ -207,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
 
@@ -216,6 +245,13 @@ namespace scheduler {
      */
     void terminate(); 
 
+    /** \brief Immediately rescheduler
+
+        Calling yield() will cause the scheduler to terminate the current queue run and immediately
+        rescheduler all pending tasks.
+     */
+    void yield();
+
     /** \brief Return timestamp of last event
 
         This is the timestamp, the last event has been signaled. This is the real time at which the
@@ -223,14 +259,39 @@ 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 Current task watchdog timeout */
-    unsigned taskTimeout(); 
+    /** \brief Number of watchdog events 
 
-    /** \brief Number of watchdog events */
-    unsigned hangCount(); 
+        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
         
@@ -258,6 +319,10 @@ namespace scheduler {
      */
     bool haveScalableHiresTimers();
 
+    /** \brief Return \c true, if using hires times, \c false otherwise
+        \see hiresTimers() */
+    bool usingHiresTimers();
+
     /** \brief Restart scheduler
         
         This call will restart all scheduler dispatchers (timers, signals, file descriptors). This
@@ -266,7 +331,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
@@ -287,6 +352,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////////////////////////////////////////