Scheduler: Implement new file descriptor event API
[senf.git] / Scheduler / Scheduler.hh
index 8c73cda..7f66821 100644 (file)
 #define HH_Scheduler_ 1
 
 // Custom includes
-#include <signal.h>
-#include <setjmp.h>
-#include <map>
-#include <queue>
-#include <boost/function.hpp>
-#include <boost/utility.hpp>
-#include <boost/call_traits.hpp>
-#include <boost/integer.hpp>
-#include "ClockService.hh"
+#include "../Utils/Logger/SenfLog.hh"
+#include "FdEvent.hh"
+#include "TimerEvent.hh"
+#include "SignalEvent.hh"
 #include "../Utils/Logger/SenfLog.hh"
 
 //#include "scheduler.mpp"
 /** \brief SENF Project namespace */
 namespace senf {
 
-    /** \brief Singleton class to manage the event loop
+    /** \brief Visible scheduler interface
 
-        The %scheduler singleton manages the central event loop. It manages and dispatches all types
-        of events managed by the scheduler library:
+        The %scheduler singleton manages access to the %scheduler library. It provides access to
+        several event dispatchers:
         \li File descriptor notifications
         \li Timeouts
         \li UNIX Signals
@@ -72,8 +67,12 @@ namespace senf {
         If you need to pass additional information to your handler, use <a
         href="http://www.boost.org/libs/bind/bind.html">Boost.Bind</a>:
         \code
+        // Handle callback function
+        void callback(UDPv4ClientSocketHandle handle, senf::Scheduler::EventId event) {..}
         // Pass 'handle' as additional first argument to callback()
-        Scheduler::instance().add(handle, boost::bind(&callback, handle, _1))
+        Scheduler::instance().add(handle, boost::bind(&callback, handle, _1), EV_READ)
+         // Timeout function
+        void timeout( int n) {..}
         // Call timeout() handler with argument 'n'
         Scheduler::instance().timeout(boost::bind(&timeout, n))
         \endcode
@@ -82,15 +81,18 @@ namespace senf {
         href="http://www.boost.org/libs/bind/bind.html">Boost.Bind</a> or senf::membind()
         \code
         // e.g. in Foo::Foo() constructor:
-        Scheduler::instance().add(handle_, senf::membind(&Foo::callback, this))
+        Scheduler::instance().add(handle_, senf::membind(&Foo::callback, this)), EV_READ)
         \endcode
-        
+
+        The handler can also be identified by an arbitrary, user specified name. This name is used
+        in error messages to identify the failing handler.
+
 
         \section sched_fd Registering file descriptors
         
         File descriptors are managed using add() or remove()
         \code
-        Scheduler::instance().add(handle, &callback);
+        Scheduler::instance().add(handle, &callback, EV_ALL);
         Scheduler::instance().remove(handle);
         \endcode 
 
@@ -122,20 +124,9 @@ namespace senf {
         Scheduler::instance().cancelTimeout(id);
         \endcode 
         Timing is based on the ClockService, which provides a high resolution and strictly
-        monotonous time source. Registering a timeout will fire the callback when the target time is
-        reached. The timer may be canceled by passing the returned \a id to cancelTimeout().
-
-        There are two parameters which adjust the exact: \a timeoutEarly and \a timeoutAdjust. \a
-        timeoutEarly is the time, a callback may be called before the deadline time is
-        reached. Setting this value below the scheduling granularity of the kernel will have the
-        %scheduler go into a <em>busy wait</em> (that is, an endless loop consuming 100% of CPU
-        recources) until the deadline time is reached! This is seldom desired. The default setting
-        of 11ms is adequate in most cases (it's slightly above the lowest linux scheduling
-        granularity). 
-
-        The other timeout scheduling parameter is \a timeoutAdjust. This value will be added to the
-        timeout value before calculating the next delay value thereby compensating for \a
-        timeoutEarly. By default, this value is set to 0 but may be changed if needed.
+        monotonous time source which again is based on POSIX timers. Registering a timeout will fire
+        the callback when the target time is reached. The timer may be canceled by passing the
+        returned \a id to cancelTimeout().
 
 
         \section sched_signals Registering POSIX/UNIX signals
@@ -152,8 +143,8 @@ namespace senf {
         A registered signal does \e not count as 'something to do'. It is therefore not possible to
         wait for signals \e only.
 
-        \todo Fix EventId parameter (probably to int) to allow |-ing without casting ...
-        
+        \todo Change the Scheduler API to use RAII. Additionally, this will remove all dynamic
+            memory allocations from the scheduler.
         \todo Fix the file support to use threads (?) fork (?) and a pipe so it works reliably even
             over e.g. NFS.
       */
@@ -175,35 +166,28 @@ namespace senf {
             \li Error flags. These additional flags may be passed to a handler to pass an error
                 condition to the handler. 
          */
-        enum EventId { 
-            EV_NONE  =  0   /**< No event */
-          , EV_READ  =  1   /**< File descriptor is readable */
-          , EV_PRIO  =  2   /**< File descriptor has OOB data */
-          , EV_WRITE =  4   /**< File descriptor is writable */
-          , EV_ALL   =  7   /**< Used to register all events at once (read/prio/write) */
-          , EV_HUP   =  8   /**< Hangup condition on file handle */
-          , EV_ERR   = 16   /**< Error condition on file handle */
+        enum EventId {
+            EV_NONE  = 0                              /**< No event */
+          , EV_READ  = scheduler::FdManager::EV_READ  /**< File descriptor is readable */
+          , EV_PRIO  = scheduler::FdManager::EV_PRIO  /**< File descriptor has OOB data */
+          , EV_WRITE = scheduler::FdManager::EV_WRITE /**< File descriptor is writable */
+          , EV_ALL   = scheduler::FdManager::EV_READ
+                     | scheduler::FdManager::EV_PRIO
+                     | scheduler::FdManager::EV_WRITE /**< Used to register all events at once
+                                                           (read/prio/write) */
+          , EV_HUP   = scheduler::FdManager::EV_HUP   /**< Hangup condition on file handle */
+          , EV_ERR   = scheduler::FdManager::EV_ERR   /**< Error condition on file handle */
         };
 
-        /** \brief Template typedef for Callback type
-
-            This is a template typedef (which does not exist in C++) that is, a template class whose
-            sole member is a typedef symbol defining the callback type given the handle type.
-
-            The Callback is any callable object taking a \c Handle and an \c EventId as argument.
-            \code
-            template <class Handle>
-            struct GenericCallback {
-                typedef boost::function<void (typename boost::call_traits<Handle>::param_type,
-                                              EventId) > Callback;
-            };
-            \endcode
-         */
-        typedef boost::function<void (EventId)> FdCallback;
+        /** \brief Callback type for file descriptor events */
+        typedef boost::function<void (int)> FdCallback;
 
         /** \brief Callback type for timer events */
         typedef boost::function<void ()> SimpleCallback;
 
+        /** \brief Callback type for signal events */
+        typedef boost::function<void (siginfo_t const &)> SignalCallback;
+
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
         ///@{
@@ -219,89 +203,12 @@ namespace senf {
             This static member is used to access the singleton instance. This member is save to
             return a correctly initialized %scheduler instance even if called at global construction
             time
-
-            \implementation This static member just defines the %scheduler as a static method
-                variable. The C++ standard then provides above guarantee. The instance will be
-                initialized the first time, the code flow passes the variable declaration found in
-                the instance() body.
          */
         static Scheduler & instance();
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        ///\name File Descriptors
-        ///\{
-
-        template <class Handle>
-        void add(Handle const & handle, FdCallback const & cb,
-                 int eventMask = EV_ALL); ///< Add file handle event callback
-                                        /**< add() will add a callback to the %scheduler. The
-                                             callback will be called for the given type of event on
-                                             the given  arbitrary file-descriptor or
-                                             handle-like object. If there already is a Callback
-                                             registered for one of the events requested, the new
-                                             handler will replace the old one.
-                                             \param[in] handle file descriptor or handle providing
-                                                 the Handle interface defined above.
-                                             \param[in] cb callback
-                                             \param[in] eventMask arbitrary combination via '|'
-                                                 operator of EventId designators. */
-        template <class Handle>
-        void remove(Handle const & handle, int eventMask = EV_ALL); ///< Remove event callback
-                                        /**< remove() will remove any callback registered for any of
-                                             the given events on the given file descriptor or handle
-                                             like object.
-                                             \param[in] handle file descriptor or handle providing
-                                                 the Handle interface defined above.
-                                             \param[in] eventMask arbitrary combination via '|'
-                                                 operator of EventId designators. */
-
-        ///\}
-
-        ///\name Timeouts
-        ///\{
-
-        unsigned timeout(ClockService::clock_type timeout, SimpleCallback const & cb); 
-                                        ///< Add timeout event
-                                        /**< \param[in] timeout timeout in nanoseconds
-                                             \param[in] cb callback to call after \a timeout
-                                                 milliseconds */
-
-        void cancelTimeout(unsigned id); ///< Cancel timeout \a id
-
-        ClockService::clock_type timeoutEarly() const;
-                                        ///< Fetch the \a timeoutEarly parameter
-        void timeoutEarly(ClockService::clock_type v);
-                                        ///< Set the \a timeoutEarly parameter
-
-        ClockService::clock_type timeoutAdjust() const;\
-                                        ///< Fetch the \a timeoutAdjust parameter
-        void timeoutAdjust(ClockService::clock_type v);
-                                        ///< Set the \a timeoutAdjust parameter
-
-        ///\}
-
-        ///\name Signal handlers
-        ///\{
-        
-        void registerSignal(unsigned signal, SimpleCallback const & cb);
-                                        ///< Add signal handler
-                                        /**< \param[in] signal signal number to register handler for
-                                             \param[in] cb callback to call whenever \a signal is
-                                                 delivered. */
-
-        void unregisterSignal(unsigned signal);
-                                        ///< Remove signal handler for \a signal
-
-        /// The signal number passed to registerSignal or unregisterSignal is invalid
-        struct InvalidSignalNumberException : public senf::Exception
-        { InvalidSignalNumberException() 
-              : senf::Exception("senf::Scheduler::InvalidSignalNumberException"){} };
-
-
-        ///\}
-
         void process();                 ///< Event handler main loop
                                         /**< This member must be called at some time to enter the
                                              event handler main loop. Only while this function is
@@ -315,104 +222,25 @@ namespace senf {
                                              returns. */
         
         ClockService::clock_type eventTime() const; ///< Return date/time of last event
+                                        /**< This is the timestamp, the last event has been
+                                             signaled. This is the real time at which the event is
+                                             delivered \e not the time it should have been delivered
+                                             (in the case of timers). */
+
+        void taskTimeout(unsigned ms);
+        unsigned taskTimeout() const;
+        unsigned hangCount() const;
+
+        void restart();
 
     protected:
 
     private:
         Scheduler();
 
-        void do_add(int fd, FdCallback const & cb, int eventMask = EV_ALL);
-        void do_remove(int fd, int eventMask = EV_ALL);
-
-        void registerSigHandlers();
-        static void sigHandler(int signal, ::siginfo_t * siginfo, void *);
-
-#       ifndef DOXYGEN
-
-        /** \brief Descriptor event specification
-            \internal */
-        struct EventSpec
-        {
-            FdCallback cb_read;
-            FdCallback cb_prio;
-            FdCallback cb_write;
-
-            EventSpec() : file(false) {}
-
-            int epollMask() const;
-
-            bool file;
-        };
-
-        /** \brief Timer event specification
-            \internal */
-        struct TimerSpec
-        {
-            TimerSpec() : timeout(), cb() {}
-            TimerSpec(ClockService::clock_type timeout_, SimpleCallback cb_, unsigned id_)
-                : timeout(timeout_), cb(cb_), id(id_), canceled(false) {}
-
-            bool operator< (TimerSpec const & other) const
-                { return timeout > other.timeout; }
-
-            ClockService::clock_type timeout;
-            SimpleCallback cb;
-            unsigned id;
-            bool canceled;
-        };
-
-#       endif 
-
-        typedef std::map<int,EventSpec> FdTable;
-        typedef std::map<unsigned,TimerSpec> TimerMap; // sorted by id
-        typedef std::vector<unsigned> FdEraseList;
-
-#       ifndef DOXYGEN
-
-        struct TimerSpecCompare
-        {
-            typedef TimerMap::iterator first_argument_type;
-            typedef TimerMap::iterator second_argument_type;
-            typedef bool result_type;
-            
-            result_type operator()(first_argument_type a, second_argument_type b);
-        };
-
-#       endif
-
-        typedef std::priority_queue<TimerMap::iterator, std::vector<TimerMap::iterator>, 
-                                    TimerSpecCompare> TimerQueue; // sorted by time
-
-        typedef std::vector<SimpleCallback> SigHandlers;
-
-        FdTable fdTable_;
-        FdEraseList fdErase_;
-        unsigned files_;
-
-        unsigned timerIdCounter_;
-        TimerQueue timerQueue_;
-        TimerMap timerMap_;
-
-        SigHandlers sigHandlers_;
-        ::sigset_t sigset_;
-        int sigpipe_[2];
-
-        int epollFd_;
         bool terminate_;
-        ClockService::clock_type eventTime_;
-        ClockService::clock_type eventEarly_;
-        ClockService::clock_type eventAdjust_;
     };
 
-    /** \brief Default file descriptor accessor
-
-        retrieve_filehandle() provides the %scheduler with support for explicit file descriptors as
-        file handle argument.
-
-        \relates Scheduler
-     */
-    int retrieve_filehandle(int fd);
-
     /** \brief %scheduler specific time source for Utils/Logger framework
 
         This time source may be used to provide timing information for log messages within the
@@ -421,7 +249,7 @@ namespace senf {
      */
     struct SchedulerLogTimeSource : public senf::log::TimeSource
     {
-        boost::posix_time::ptime operator()() const;
+        senf::log::time_type operator()() const;
     };
 
 }
@@ -429,7 +257,7 @@ namespace senf {
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Scheduler.cci"
 //#include "Scheduler.ct"
-#include "Scheduler.cti"
+//#include "Scheduler.cti"
 #endif
 
 \f