X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Scheduler%2FScheduler.hh;h=9f3d3cd2f3715f9c0156a9c5c1c9d8409c62c955;hb=532240d72e09e19e57fac9bb55c2560b9c9e5b97;hp=a8cfe59f3629b6e50190aef537a218d4e3e00a25;hpb=412024ed31a4ab4eaea7a4165a434f8efebee325;p=senf.git diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index a8cfe59..9f3d3cd 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -28,6 +28,7 @@ #define HH_SENF_Scheduler_Scheduler_ 1 // Custom includes +#include #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 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 @@ -223,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 @@ -240,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 @@ -261,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////////////////////////////////////////