e5c045c550353fab4a796023dd5419d0c999003b
[senf.git] / Scheduler / Scheduler.hh
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Scheduler public header
25  */
26
27 #ifndef HH_Scheduler_
28 #define HH_Scheduler_ 1
29
30 // Custom includes
31 #include <map>
32 #include <queue>
33 #include <boost/function.hpp>
34 #include <boost/utility.hpp>
35 #include <boost/call_traits.hpp>
36 #include <boost/integer.hpp>
37 #include "ClockService.hh"
38
39 //#include "scheduler.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 /** \brief SENF Project namespace */
43 namespace senf {
44
45     /** \brief Singleton class to manage the event loop
46
47         This class manages a single select() type event loop. A customer of this class may register
48         any number of file descriptors with this class and pass callback functions to be called on
49         input, output or error. This functions are specified using boost::function objects (See <a
50         href="http://www.boost.org/doc/html/function.html">Boost.Function</a>)
51
52         The Scheduler is based on a generic handle representation. The only information needed from
53         a handle, is the intrinsic file descriptor. Any object for which the statement
54         \code
55           int fd = retrieve_filehandle(object);
56         \endcode
57         is valid and places the relevant file descriptor into fd can be used as a Handle type. There
58         is an implementation of retrieve_filehandle(int) within the library to handle explicit file
59         descriptors. The <a href="../../../Socket/doc/html/index.html">Socket library</a> provides an
60         implementation of <tt>retrieve_filehandle(FileHandle handle)</tt>. If you want to support
61         some other handle type, just define an appropriate \c retrieve_filehandle function <em>in
62         that types namespace</em>.
63
64         It is important to note, that for every combination of file descriptor and event, only a \e
65         single handler may be installed. Installing more handlers does not make sense. If you need
66         to distribute data to several interested parties, you must take care of this yourself.
67
68         \todo Fix EventId parameter (probably to int) to allow |-ing without casting ...
69       */
70     class Scheduler
71         : boost::noncopyable
72     {
73     public:
74         ///////////////////////////////////////////////////////////////////////////
75         // Types
76
77         /** \brief Types of file descriptor events */
78         enum EventId { EV_NONE=0,
79                        EV_READ=1, EV_PRIO=2, EV_WRITE=4, 
80                        EV_ALL=7,
81                        EV_HUP=8, EV_ERR=16 };
82
83         /** \brief Template typedef for Callback type
84
85             This is a template typedef (which does not exist in C++) that is, a template class whose
86             sole member is a typedef symbol defining the callback type given the handle type.
87
88             The Callback is any callable object taking a \c Handle and an \c EventId as argument.
89          */
90         template <class Handle>
91         struct GenericCallback {
92             typedef boost::function<void (typename boost::call_traits<Handle>::param_type,
93                                           EventId) > Callback;
94         };
95
96         /** \brief Callback type for timer events */
97         typedef boost::function<void ()> TimerCallback;
98
99         ///////////////////////////////////////////////////////////////////////////
100         ///\name Structors and default members
101         ///@{
102
103         // private default constructor
104         // no copy constructor
105         // no copy assignment
106         // default destructor
107         // no conversion constructors
108
109         /** \brief Return Scheduler instance
110
111             This static member is used to access the singleton instance. This member is save to
112             return a correctly initialized Scheduler instance even if called at global construction
113             time
114
115             \implementation This static member just defines the Scheduler as a static method
116                 variable. The C++ standard then provides above guarantee. The instance will be
117                 initialized the first time, the code flow passes the variable declaration found in
118                 the instance() body.
119
120             \fixme TimerQueue as \c map \e and \c priority_queue doesn't make sense ...
121          */
122         static Scheduler & instance();
123
124         ///@}
125         ///////////////////////////////////////////////////////////////////////////
126
127         template <class Handle>
128         void add(Handle const & handle,
129                  typename GenericCallback<Handle>::Callback const & cb,
130                  int eventMask = EV_ALL); ///< Add file handle event callback
131                                         /**< add() will add a callback to the Scheduler. The
132                                              callback will be called for the given type of event on
133                                              the given  arbitrary file-descriptor or
134                                              handle-like object. If there already is a Callback
135                                              registered for one of the events requested, the new
136                                              handler will replace the old one.
137                                              \param[in] handle file descriptor or handle providing
138                                                  the Handle interface defined above.
139                                              \param[in] cb callback
140                                              \param[in] eventMask arbitrary combination via '|'
141                                                  operator of EventId designators. */
142         template <class Handle>
143         void remove(Handle const & handle, int eventMask = EV_ALL); ///< Remove event callback
144                                         /**< remove() will remove any callback registered for any of
145                                              the given events on the given file descriptor or handle
146                                              like object.
147                                              \param[in] handle file descriptor or handle providing
148                                                  the Handle interface defined above.
149                                              \param[in] eventMask arbitrary combination via '|'
150                                                  operator of EventId designators. */
151
152         unsigned timeout(ClockService::clock_type timeout, TimerCallback const & cb); 
153                                         ///< Add timeout event
154                                         /**< \param[in] timeout timeout in nanoseconds
155                                              \param[in] cb callback to call after \a timeout
156                                                  milliseconds
157                                              \todo Return some kind of handle/pointer and add
158                                                  support to update or revoke a timeout */
159
160         void cancelTimeout(unsigned id);
161
162         void process();                 ///< Event handler main loop
163                                         /**< This member must be called at some time to enter the
164                                              event handler main loop. Only while this function is
165                                              running any events are handled. The call will return
166                                              only, if any callback calls terminate(). */
167         void terminate();               ///< Called by callbacks to terminate the main loop
168                                         /**< This member may be called by any callback to tell the
169                                              main loop to terminate. The main loop will return to
170                                              it's caller after the currently running callback
171                                              returns. */
172         
173         ClockService::clock_type eventTime() const; ///< Return date/time of last event
174
175     protected:
176
177     private:
178         typedef boost::function<void (EventId)> SimpleCallback;
179
180         Scheduler();
181
182         void do_add(int fd, SimpleCallback const & cb, int eventMask = EV_ALL);
183         void do_remove(int fd, int eventMask = EV_ALL);
184
185         /** \brief Descriptor event specification
186             \internal */
187         struct EventSpec
188         {
189             SimpleCallback cb_read;
190             SimpleCallback cb_prio;
191             SimpleCallback cb_write;
192
193             int epollMask() const;
194         };
195
196         /** \brief Timer event specification
197             \internal */
198         struct TimerSpec
199         {
200             TimerSpec() : timeout(), cb() {}
201             TimerSpec(ClockService::clock_type timeout_, TimerCallback cb_, unsigned id_)
202                 : timeout(timeout_), cb(cb_), id(id_), canceled(false) {}
203
204             bool operator< (TimerSpec const & other) const
205                 { return timeout > other.timeout; }
206
207             ClockService::clock_type timeout;
208             TimerCallback cb;
209             unsigned id;
210             bool canceled;
211         };
212
213         typedef std::map<int,EventSpec> FdTable;
214         typedef std::map<unsigned,TimerSpec> TimerMap;
215
216         struct TimerSpecCompare
217         {
218             typedef TimerMap::iterator first_argument_type;
219             typedef TimerMap::iterator second_argument_type;
220             typedef bool result_type;
221             
222             result_type operator()(first_argument_type a, second_argument_type b);
223         };
224
225         typedef std::priority_queue<TimerMap::iterator, std::vector<TimerMap::iterator>, 
226                                     TimerSpecCompare> TimerQueue;
227
228         FdTable fdTable_;
229         unsigned timerIdCounter_;
230         TimerQueue timerQueue_;
231         TimerMap timerMap_;
232         int epollFd_;
233         bool terminate_;
234         ClockService::clock_type eventTime_;
235     };
236
237     /** \brief Default file descriptor accessor
238
239         retrieve_filehandle() provides the Scheduler with support for explicit file descriptors as
240         file handle argument.
241
242         \relates Scheduler
243      */
244     int retrieve_filehandle(int fd);
245
246 }
247
248 ///////////////////////////////hh.e////////////////////////////////////////
249 #include "Scheduler.cci"
250 //#include "Scheduler.ct"
251 #include "Scheduler.cti"
252 #endif
253
254 \f
255 // Local Variables:
256 // mode: c++
257 // fill-column: 100
258 // c-file-style: "senf"
259 // indent-tabs-mode: nil
260 // ispell-local-dictionary: "american"
261 // compile-command: "scons -u test"
262 // comment-column: 40
263 // End: