Utils/Console: Fix singleton instantiation order (ServerManager / Scheduler)
[senf.git] / Scheduler / Scheduler.hh
index ba077e4..89e9d23 100644 (file)
@@ -1,9 +1,9 @@
 // $Id$
 //
 // Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-//     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 #define HH_Scheduler_ 1
 
 // Custom includes
-#include <map>
-#include <queue>
-#include <boost/function.hpp>
-#include <boost/utility.hpp>
-#include <boost/call_traits.hpp>
-#include <boost/integer.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "../Utils/Logger/SenfLog.hh"
+#include "FdDispatcher.hh"
+#include "TimerDispatcher.hh"
+#include "SignalDispatcher.hh"
+#include "FileDispatcher.hh"
+#include "../Utils/Logger/SenfLog.hh"
 
 //#include "scheduler.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 /** \brief SENF Project namespace */
 namespace senf {
 
-    /** \brief Singleton class to manage the event loop
+    /** \brief Visible scheduler interface
 
-        This class manages a single select() type event loop. A customer of this class may register
-        any number of file descriptors with this class and pass callback functions to be called on
-        input, output or error. This functions are specified using boost::function objects (See <a
-        href="http://www.boost.org/doc/html/function.html">Boost.Function</a>)
+        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
 
-        The Scheduler is based on a generic handle representation. The only information needed from
-        a handle, is the intrinsic file descriptor. Any object for which the statement
+        The %scheduler is entered by calling it's process() member. This call will continue to run as
+        long as there is something to do, or until one of the handlers calls terminate(). The
+        %scheduler has 'something to do' as long as there is any file descriptor or timeout active.
+
+        The %scheduler only provides low level primitive scheduling capability. Additional helpers
+        are defined on top of this functionality (e.g. ReadHelper or WriteHelper or the interval
+        timers of the PPI).
+
+
+        \section sched_handlers Specifying handlers
+
+        All handlers are passed as generic <a
+        href="http://www.boost.org/doc/html/function.html">Boost.Function</a> objects. This allows
+        to pass any callable as a handler. Depending on the type of handler, some additional
+        arguments may be passed to the handler by the %scheduler. 
+
+        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
-          int fd = retrieve_filehandle(object);
+        // 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), EV_READ)
+         // Timeout function
+        void timeout( int n) {..}
+        // Call timeout() handler with argument 'n'
+        Scheduler::instance().timeout(boost::bind(&timeout, n))
         \endcode
-        is valid and places the relevant file descriptor into fd can be used as a Handle type. There
-        is an implementation of retrieve_filehandle(int) within the library to handle explicit file
-        descriptors. The <a href="../../../Socket/doc/html/index.html">Socket library</a> provides an
-        implementation of <tt>retrieve_filehandle(FileHandle handle)</tt>. If you want to support
-        some other handle type, just define an appropriate \c retrieve_filehandle function <em>in
-        that types namespace</em>.
-
-        It is important to note, that for every combination of file descriptor and event, only a \e
-        single handler may be installed. Installing more handlers does not make sense. If you need
-        to distribute data to several interested parties, you must take care of this yourself.
-
-        \todo Fix EventId parameter (probably to int) to allow |-ing without casting ...
+
+        To use member-functions as callbacks, use either <a
+        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)), 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, EV_ALL);
+        Scheduler::instance().remove(handle);
+        \endcode 
+
+        The callback will be called with one additional argument. This argument is the event mask of
+        type EventId. This mask will tell, which of the registered events are signaled. The
+        additional flags EV_HUP or EV_ERR (on hangup or error condition) may be set additionally.
+
+        Only a single handler may be registered for any combination of file descriptor and event
+        (registering multiple callbacks for a single fd and event does not make sense).
+
+        The %scheduler will accept any object as \a handle argument as long as retrieve_filehandle()
+        may be called on that object
+        \code
+        int fd = retrieve_filehandle(handle);
+        \endcode 
+        to fetch the file handle given some abstract handle type. retrieve_filehandle() will be
+        found using ADL depending on the argument namespace. A default implementation is provided
+        for \c int arguments (file descriptors)
+
+
+        \section sched_timers Registering timers
+
+        The %scheduler has very simple timer support. There is only one type of timer: A single-shot
+        deadline timer. More complex timers are built based on this. Timers are managed using
+        timeout() and cancelTimeout()
+        \code
+        int id = Scheduler::instance().timeout(Scheduler::instance().eventTime() + ClockService::milliseconds(100),
+                                               &callback);
+        Scheduler::instance().cancelTimeout(id);
+        \endcode 
+        Timing is based on the ClockService, which provides a high resolution and strictly
+        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
+
+        The %scheduler also incorporates standard POSIX/UNIX signals. Signals registered with the
+        %scheduler will be handled \e synchronously within the event loop.
+        \code
+        Scheduler::instance().registerSignal(SIGUSR1, &callback);
+        Scheduler::instance().unregisterSignal(SIGUSR1);
+        \endcode
+        When registering a signal with the %scheduler, that signal will automatically be blocked so
+        it can be handled within the %scheduler. 
+
+        A registered signal does \e not count as 'something to do'. It is therefore not possible to
+        wait for signals \e only.
+
+        \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.
       */
     class Scheduler
         : boost::noncopyable
     {
     public:
-        ///////////////////////////////////////////////////////////////////////////
-        // Types
 
-        /** \brief Types of file descriptor events */
-        enum EventId { EV_NONE=0,
-                       EV_READ=1, EV_PRIO=2, EV_WRITE=4, 
-                       EV_ALL=7,
-                       EV_HUP=8, EV_ERR=16 };
+        SENF_LOG_CLASS_AREA();
 
-        /** \brief Template typedef for Callback type
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
 
-            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.
+        /** \brief Types of file descriptor events 
 
-            The Callback is any callable object taking a \c Handle and an \c EventId as argument.
+            These events are grouped into to classes:
+            \li Ordinary file descriptor events for which handlers may be registered. These are
+                EV_READ, EV_PRIO and EV_WRITE. EV_ALL is a combination of these three.
+            \li Error flags. These additional flags may be passed to a handler to pass an error
+                condition to the handler. 
          */
-        template <class Handle>
-        struct GenericCallback {
-            typedef boost::function<void (typename boost::call_traits<Handle>::param_type,
-                                          EventId) > Callback;
+        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 Scheduler time data type
-            
-            Unsigned integer type representing scheduler time. Scheduler time is measured in
-            nanoseconds relative to some implementation defined reference time.
-         */
-        typedef boost::uint_fast64_t sched_time;
+        /** \brief Callback type for file descriptor events */
+        typedef boost::function<void (int)> FdCallback;
 
-        /** \brief Absolute time data type
+        /** \brief Callback type for timer events */
+        typedef boost::function<void ()> SimpleCallback;
 
-            Boost.DateTime datatype used to represent absolute date/time values.
-         */
-        typedef boost::posix_time::ptime abs_time;
+        /** \brief Callback type for signal events */
+        typedef boost::function<void (siginfo_t const &)> SignalCallback;
 
-        /** \brief Callback type for timer events */
-        typedef boost::function<void ()> TimerCallback;
+        /** \brief Timer id type */
+        typedef scheduler::TimerDispatcher::timer_id timer_id;
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -119,37 +202,44 @@ namespace senf {
         // default destructor
         // no conversion constructors
 
-        /** \brief Return Scheduler instance
+        /** \brief Return %scheduler instance
 
             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
+            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,
-                 typename GenericCallback<Handle>::Callback const & cb,
-                 int eventMask = EV_ALL); ///< Add file handle event callback
-                                        /**< add() will add a callback to the Scheduler. The
+        void add(std::string const & name, 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] name descriptive name to identify the
+                                                 callback.
                                              \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. */
+                                                 operator of \ref senf::Scheduler::EventId "EventId"
+                                                 designators. */
+        template <class Handle>        
+        void add(Handle const & handle, FdCallback const & cb,
+                 int eventMask = EV_ALL); ///< Add file handle event callback
+                                        /**< \see add() */
+
+
         template <class Handle>
         void remove(Handle const & handle, int eventMask = EV_ALL); ///< Remove event callback
                                         /**< remove() will remove any callback registered for any of
@@ -158,103 +248,114 @@ namespace senf {
                                              \param[in] handle file descriptor or handle providing
                                                  the Handle interface defined above.
                                              \param[in] eventMask arbitrary combination via '|'
-                                                 operator of EventId designators. */
+                                                 operator of \ref senf::Scheduler::EventId "EventId"
+                                                 designators. */
+
+        ///\}
 
-        void timeout(sched_time timeout, TimerCallback const & cb); ///< Add timeout event
-                                        /**< \param[in] timeout timeout in nanoseconds
+        ///\name Timeouts
+        ///\{
+
+        timer_id timeout(std::string const & name, ClockService::clock_type timeout, 
+                         SimpleCallback const & cb); 
+                                        ///< Add timeout event
+                                        /**< \returns timer id
+                                             \param[in] name descriptive name to identify the
+                                                 callback.
+                                             \param[in] timeout timeout in nanoseconds
                                              \param[in] cb callback to call after \a timeout
-                                                 milliseconds
-                                             \todo Return some kind of handle/pointer and add
-                                                 support to update or revoke a timeout */
+                                                 milliseconds */
+
+        timer_id timeout(ClockService::clock_type timeout, SimpleCallback const & cb); 
+                                        ///< Add timeout event
+                                        /**< \see timeout() */
+
+        void cancelTimeout(timer_id id); ///< Cancel timeout \a id
+
+#ifndef DOXYGEN
+        ClockService::clock_type timeoutEarly() const;
+        void timeoutEarly(ClockService::clock_type v);
+
+        ClockService::clock_type timeoutAdjust() const;
+        void timeoutAdjust(ClockService::clock_type v);
+#endif
+
+        ///\}
+
+        ///\name Signal handlers
+        ///\{
+        
+        void registerSignal(unsigned signal, SignalCallback 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
+
+        ///\}
 
         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
                                              running any events are handled. The call will return
                                              only, if any callback calls terminate(). */
+
         void terminate();               ///< Called by callbacks to terminate the main loop
                                         /**< This member may be called by any callback to tell the
                                              main loop to terminate. The main loop will return to
                                              it's caller after the currently running callback
                                              returns. */
         
-        abs_time abstime(sched_time time) const; ///< Convert scheduler time to absolute time
-                                        /**< This member converts a scheduler time value into an
-                                             absolute Boost.DateTime value. 
-                                             \note You should not base timeout calculations on this
-                                                 absolute time value. Scheduler time is guaranteed
-                                                 to be monotonous, absolute time may be
-                                                 non-monotonous if the system date/time is
-                                                 changed. */
-
-        sched_time schedtime(abs_time time) const; ///< Convert absolute time to scheduler time
-                                        /**< This member converst an absolute time value into the
-                                             corresponding scheduler time.
-                                             \see abstime */
-
-        sched_time now() const;         ///< Return current date/time
-                                        /**< The return value represents the current date/time in
-                                             scheduler time representation */
-
-        sched_time eventTime() const;   ///< Return date/time of last event
+        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). */
+
+        unsigned hangCount() const;
 
     protected:
 
     private:
-        typedef boost::function<void (EventId)> SimpleCallback;
-
-        static unsigned const MinTimeout = 1000;
-
         Scheduler();
 
-        void do_add(int fd, SimpleCallback const & cb, int eventMask = EV_ALL);
-        void do_remove(int fd, int eventMask = EV_ALL);
-
-        /** \brief Descriptor event specification
-            \internal */
-        struct EventSpec
-        {
-            SimpleCallback cb_read;
-            SimpleCallback cb_prio;
-            SimpleCallback cb_write;
-
-            int epollMask() const;
-        };
-
-        /** \brief Timer event specification
-            \internal */
-        struct TimerSpec
-        {
-            TimerSpec() : timeout(), cb() {}
-            TimerSpec(sched_time timeout_, TimerCallback cb_)
-                : timeout(timeout_), cb(cb_) {}
-
-            bool operator< (TimerSpec const & other) const
-                { return timeout > other.timeout; }
+        void do_add(int fd, FdCallback const & cb, int eventMask = EV_ALL);
+        void do_add(std::string const & name, int fd, FdCallback const & cb, 
+                    int eventMask = EV_ALL);
+        void do_remove(int fd, int eventMask);
 
-            sched_time timeout;
-            TimerCallback cb;
-        };
-
-        typedef std::map<int,EventSpec> FdTable;
-        typedef std::priority_queue<TimerSpec> TimerQueue;
-
-        FdTable fdTable_;
-        TimerQueue timerQueue_;
-        int epollFd_;
         bool terminate_;
-        abs_time epoch_;
+        scheduler::FdManager manager_;
+        scheduler::FIFORunner runner_;
+
+        scheduler::FdDispatcher fdDispatcher_;
+        scheduler::TimerDispatcher timerDispatcher_;
+        scheduler::SignalDispatcher signalDispatcher_;
+        scheduler::FileDispatcher fileDispatcher_;
     };
 
     /** \brief Default file descriptor accessor
 
-        retrieve_filehandle() provides the Scheduler with support for explicit file descriptors as
+        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
+        Utils/Logger framework. This time source will use Scheduler::eventTime() to provide timing
+        information.
+     */
+    struct SchedulerLogTimeSource : public senf::log::TimeSource
+    {
+        senf::log::time_type operator()() const;
+    };
+
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////