]> git.llucax.com Git - software/eventxx.git/blob - eventxx
Acknowledge test ported from libevent and add a missing test to doxygen documentation.
[software/eventxx.git] / eventxx
1 #ifndef _EVENTXX_HPP_
2 #define _EVENTXX_HPP_
3
4 #include <sys/types.h> // timeval
5 #include <stdexcept>   // std::exception, std::invalid_argument,
6                        // std::runtime_error, std::bad_alloc
7
8 /** @mainpage
9  *
10  * @section Introduction
11  *
12  * The <a href="http://monkey.org/~provos/libevent/">libevent</a> API provides
13  * a mechanism to execute a callback function when a specific event occurs on
14  * a file descriptor or after a timeout has been reached. Furthermore, libevent
15  * also support callbacks due to signals or regular timeouts.
16  *
17  * libevent is meant to replace the event loop found in event driven network
18  * servers. An application just needs to call dispatcher::dispatch() and then
19  * add or remove events dynamically without having to change the event loop.
20  *
21  * Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
22  * epoll(4). It also has experimental support for real-time signals. The
23  * internal event mechanism is completely independent of the exposed event API,
24  * and a simple update of libevent can provide new functionality without having
25  * to redesign the applications. As a result, Libevent allows for portable
26  * application development and provides the most scalable event notification
27  * mechanism available on an operating system. Libevent should compile on Linux,
28  * *BSD, Mac OS X, Solaris and Windows.
29  *
30  * This is a simple, direct, one-header inline C++ wrapper for libevent. Yes,
31  * it's just one header file, so if you want to use it you can just copy the
32  * file to your project and you are set.
33  *
34  * It's designed to be as close to use to libevent (without compromising modern
35  * C++ programming techniques) and efficiency (since all implementation is
36  * trivial and inline, theoretically, it imposes no overhead at all).
37  *
38  * Please, visit the <a href="http://www.llucax.com.ar/~luca/eventxx/">eventxx
39  * website</a> for the latest documentation.
40  *
41  * You can always <a href="http://www.lluca.com.ar/~lucax/repos/eventxx/">get
42  * the most up to date sources</a> from the
43  * <a href="http://www.darcs.net/">darcs</a>.
44  *
45  * You can also take a look the the <a
46  * href="http://auriga.wearlab.de/~alb/darcsweb/">darcsweb</a> interface to see
47  * the <a href="http://www.llucax.com.ar/~luca/repos/darcsweb/?r=eventxx">latest
48  * changes online</a>.
49  *
50  *
51  * @section Usage
52  *
53  * This wrapper was designed to be used just like libevent, but with C++ style
54  * syntax sugar (or poison, depends on your point of view ;) and goodies. The
55  * main difference to libevent is you always have to instance a
56  * eventxx::dispatcher to get an event loop. There is no implicit global event
57  * loop. This adds just an extra line of code for single threaded applications
58  * and makes things much more simple. See eventxx::dispatcher documentation for
59  * more details.
60  *
61  * You can use use the same plain functions callbacks or the other kind of
62  * function objects (see @link events @endlink section for details on event
63  * types).
64  *
65  * eventxx uses @link exceptions @endlink to report errors. All functions has
66  * exception specifications, so it's easy to find out what to expect. See
67  * exceptions section for more detail.
68  *
69  * A timespec abstraction is provided in eventxx::time for convenient argument
70  * passing. Even more, it's a timespec itself, with some convenient methods for
71  * accessing the timespec attributes in a more C++ way. And even more, eventxx
72  * is such a direct mapping that all eventxx::event's are libevent event structs
73  * too, so theoretically you can pass a eventxx::event to libevent C functions
74  * without much trouble. eventxx::dispatcher is the only class that is not
75  * derived from libevent struct (event_base) because this struct it's not
76  * defined on the libevent header (just declared).
77  *
78  * Maybe you shouldn't know this implementation details to keep the abstraction,
79  * but this is a basic design goal of this wrapper so there is not much chance
80  * that this changes in the future (but use this knowledge with care, you are
81  * warned ;).
82  *
83  * @section Example
84  *
85  * @code
86  * #include <eventxx>
87  * #include <iostream>
88  * #include <csignal>
89  *
90  * struct handler
91  * {
92  *      eventxx::dispatcher& d;
93  *      int i;
94  *      handler(eventxx::dispatcher& d): d(d), i(0) {}
95  *      void operator() (int signum, short event)
96  *      {
97  *              if (i < 5) std::cout << "keep going...\n";
98  *              else
99  *              {
100  *                      std::cout << "done!\n";
101  *                      d.exit();
102  *              }
103  *      }
104  * };
105  *
106  * void sighandler(int signum, short event, void* data)
107  * {
108  *      int& i = *static_cast< int* >(data);
109  *      std::cout << ++i << " interrupts, ";
110  * }
111  *
112  * int main()
113  * {
114  *      eventxx::dispatcher d;
115  *      handler h(d);
116  *      eventxx::csignal sigev(SIGINT, sighandler, &h.i);
117  *      eventxx::signal< handler > e(SIGINT, h);
118  *      d.add(sigev);
119  *      d.add(e);
120  *      d.dispatch();
121  *      return 0;
122  * }
123  * @endcode
124  *
125  * You can see some more examples on the test directory of the distribution or
126  * on the examples related page.
127  *
128  *
129  * @section Status
130  *
131  * This library was not widely used yet, it lack some testing. Because templates
132  * are not even compiled when they are used, you can't be surprised if you catch
133  * a piece of code that didn't got even compiled yet because the lack of
134  * testing. The library has no support for buffered events yet either. It
135  * doesn't support the http stuff, and probably never will because that has
136  * nothing to do with event handling.
137  *
138  * If you notice this lib leaks memory, don't blame me, blame libevent :)
139  * libevent has a known bug on event_base_free() that makes it assert always, so
140  * event_base_free() it's unusable, unless you patch your libevent (for example,
141  * using this <a
142  * href="http://monkeymail.org/archives/libevent-users/2006-April/000141.html">patch</a>
143  * written by Mark D. Anderson and who knows why it's not still applied. If you
144  * do so, you can compile your programs with -DEVENT_BASE_FREE_FIX so
145  * event_base_free() gets called.
146  *
147  * That said, I think it's pretty usable anyways. If something is broken it
148  * would be really easy to fix it because is just a simple wrapper around
149  * libevent. So, please try it out, and if you have any problems,
150  * <a href="mailto:llucax+eventxx@gmail.com">drop me an
151  * e-mail</a> and and I'll fix it ASAP (or provide a patch and you will be my
152  * best friend ;).
153  *
154  * Patches to support buffered events are welcome too.
155  *
156  *
157  * @author Leandro Lucarella <llucax+eventxx@gmail.com>
158  *
159  * @version 0.1
160  *
161  * @par License
162  * This program is under the BOLA license (see
163  * http://auriga.wearlab.de/~alb/bola/ for more info or the
164  * <a href="http://www.llucax.com.ar/~luca/repos/eventxx/LICENSE">LICENSE</a>
165  * file itself).
166  *
167  */
168
169 /** @example c-way.cpp
170  *
171  * This is a simple example illustrating the usage with C-like callback
172  * functions.
173  */
174
175 /** @example functor-way.cpp
176  *
177  * This is a simple example illustrating the usage with function object
178  * callbacks.
179  */
180
181 /** @example mixed-way.cpp
182  *
183  * This is a simple example illustrating the usage with a mix of C-like callbacks
184  * and function object callbacks.
185  */
186
187 /** @example bench.cpp
188  *
189  * This is a benchmark example, extracted from libevent and ported to eventxx.
190  */
191
192 /** @example prio-test.cpp
193  *
194  * This is a priority usage example.
195  */
196
197 /** @example test-time.cpp
198  *
199  * This is a timer usage example ported from libevent.
200  */
201
202 /** @example test-eof.cpp
203  *
204  * This is some kind of test of EOF ported from libevent.
205  */
206
207 /** @example test-weof.cpp
208  *
209  * Another test of EOF ported from libevent.
210  */
211
212 /** @example trivial.cpp
213  *
214  * This is the most trivial example.
215  */
216
217 /**
218  * Namespace for all symbols libevent C++ wrapper defines.
219  */
220 namespace eventxx
221 {
222
223
224 // All libevent C API symbols and other internal stuff goes here.
225 namespace internal
226 {
227 #include <event.h>
228 }
229
230
231 /** @defgroup exceptions Exceptions
232  *
233  * eventxx makes a heavy use of exceptions. Each function has it's exceptions
234  * specified, so it's very easy to find out what exceptions to expect.
235  *
236  * Exceptions are mostly thrown when there is a programming error. So if you get
237  * an exception check your code.
238  */
239 //@{
240
241
242 /**
243  * Base class for all libevent exceptions.
244  */
245 struct exception: public std::exception
246 {
247 };
248
249
250 /**
251  * Invalid event exception.
252  *
253  * This exception is thrown when passing an invalid event to a function, the
254  * reason is given in the what() description but it usually means that the you
255  * are making some restricted operation with an active event.
256  *
257  * If you hit this exception, you probably got a programming error.
258  */
259 struct invalid_event: public std::invalid_argument, public exception
260 {
261
262         /**
263          * Creates an invalid event exception with a reason.
264          *
265          * @param what Reason why the event is invalid).
266          */
267         explicit invalid_event(const std::string& what) throw():
268                 std::invalid_argument(what)
269         {
270         }
271
272 }; // struct invalid_event
273
274
275 /**
276  * Invalid priority exception.
277  *
278  * This exception is thrown when passing an invalid priority to a function. This
279  * usually means you don't have enough priority queues in your dispatcher, so
280  * you should have allocated more in the constructor.
281  *
282  * If you hit this exception, you probably got a programming error.
283  *
284  * @see dispatcher::dispatcher(int) to allocate more priority queues.
285  */
286 struct invalid_priority: public std::invalid_argument, public exception
287 {
288
289         /**
290          * Creates an invalid priority exception with a reason.
291          *
292          * @param what Reason why the priority is invalid).
293          */
294         explicit invalid_priority(const std::string& what
295                         = "invalid priority value") throw():
296                 std::invalid_argument(what)
297         {
298         }
299
300 }; // struct invalid_priority
301
302 //@}
303
304
305 /// Miscellaneous constants
306 enum
307 {
308         DEFAULT_PRIORITY = -1,      ///< Default priority (the middle value).
309         ONCE = EVLOOP_ONCE,         ///< Loop just once.
310         NONBLOCK = EVLOOP_NONBLOCK  ///< Don't block the event loop.
311 };
312
313
314 /// C function used as callback in the C API.
315 typedef void (*ccallback_type)(int, short, void*);
316
317
318 /**
319  * Time used for timeout values.
320  *
321  * This timeout is compose of seconds and microseconds.
322  */
323 struct time: ::timeval
324 {
325
326         /**
327          * Creates a new time with @p sec seconds and @p usec microseconds.
328          *
329          * @param sec Number of seconds.
330          * @param usec Number of microseconds.
331          */
332         time(long sec = 0l, long usec = 0l) throw()
333                 { tv_sec = sec; tv_usec = usec; }
334
335         /**
336          * Gets the number of seconds.
337          *
338          * @return Number of seconds.
339          */
340         long sec() const throw() { return tv_sec; };
341
342         /**
343          * Gets the number of microseconds.
344          *
345          * @return Number of microseconds.
346          */
347         long usec() const throw() { return tv_usec; };
348
349         /**
350          * Sets the number of seconds.
351          *
352          * @param s Number of seconds.
353          */
354         void sec(long s) throw() { tv_sec = s; };
355
356         /**
357          * Sets the number of microseconds.
358          *
359          * @param u Number of microseconds.
360          */
361         void usec(long u) throw() { tv_usec = u; };
362
363 }; // struct time
364
365
366 /** @defgroup events Events
367  *
368  * There are many ways to specify how to handle an event. You can use use the
369  * same plain functions callbacks (see eventxx::cevent, eventxx::ctimer and
370  * eventxx::csignal) like in C or the other kind of more advanced, stateful
371  * function objects (see eventxx::event, eventxx::timer and eventxx::signal
372  * templates). The former are just typedef'ed specialization of the later.
373  *
374  * All events derive from a plain class (not template) eventxx::basic_event, one
375  * of the main utilities of it (besides containing common code ;) is to be used
376  * in STL containers.
377  *
378  * Please see each class documentation for details and examples.
379  */
380 //@{
381
382 /**
383  * Type of events.
384  *
385  * There are 4 kind of events: eventxx::TIMEOUT, eventxx::READ, eventxx::WRITE
386  * or eventxx::SIGNAL. eventxx::PERSIST is not an event, is an event modifier
387  * flag, that tells eventxx that this event should live until dispatcher::del()
388  * is called. You can use, for example:
389  * @code
390  * eventxx::event(fd, eventxx::READ | eventxx::PERSIST, ...);
391  * @endcode
392  */
393 enum type
394 {
395         TIMEOUT = EV_TIMEOUT, ///< Timeout event.
396         READ = EV_READ,       ///< Read event.
397         WRITE = EV_WRITE,     ///< Write event.
398         SIGNAL = EV_SIGNAL,   ///< Signal event.
399         PERSIST = EV_PERSIST  ///< Not really an event, is an event modifier.
400 };
401
402 /**
403  * Basic event from which all events derive.
404  *
405  * All events derive from this class, so it's useful for use in containers,
406  * like:
407  * @code
408  * std::list< eventxx::basic_event* > events;
409  * @endcode
410  */
411 struct basic_event: internal::event
412 {
413
414         /**
415          * Checks if there is an event pending.
416          *
417          * @param ev Type of event to check.
418          *
419          * @return true if there is a pending event, false if not.
420          */
421         bool pending(type ev) const throw()
422         {
423                 // HACK libevent don't use const
424                 return event_pending(const_cast< basic_event* >(this), ev, 0);
425         }
426
427         /**
428          * Timeout of the event.
429          *
430          * @return Timeout of the event.
431          */
432         time timeout() const throw()
433         {
434                 time tv;
435                 // HACK libevent don't use const
436                 event_pending(const_cast< basic_event* >(this), EV_TIMEOUT, &tv);
437                 return tv;
438         }
439
440         /**
441          * Sets the event's priority.
442          *
443          * @param priority New event priority.
444          *
445          * @pre The event must be added to some dispatcher.
446          *
447          * @see dispatcher::dispatcher(int)
448          */
449         void priority(int priority) const throw(invalid_event, invalid_priority)
450         {
451                 if (ev_flags & EVLIST_ACTIVE)
452                         throw invalid_event("can't change the priority of an "
453                                         "active event");
454                 // HACK libevent don't use const
455                 if (event_priority_set(const_cast< basic_event* >(this),
456                                         priority))
457                         throw invalid_priority();
458         }
459
460         /**
461          * Event's file descriptor.
462          *
463          * @return Event's file descriptor.
464          */
465         int fd() const throw()
466         {
467                 return EVENT_FD(this);
468         }
469
470         /// @note This is an abstract class, you can't instantiate it.
471         protected:
472                 basic_event() throw() {}
473                 basic_event(const basic_event&);
474                 basic_event& operator= (const basic_event&);
475
476 }; // struct basic_event
477
478
479 /**
480  * Generic event object.
481  *
482  * This object stores all the information about an event, including a callback
483  * functor, which is called when the event is fired. The template parameter
484  * must be a functor (callable object or function) that can take 2 parameters:
485  * an integer (the file descriptor of the fired event) and an event::type (the
486  * type of event being fired).
487  * There is a specialized version of this class which takes as the template
488  * parameter a C function with the ccallback_type signature, just like C
489  * libevent API does.
490  *
491  * @see eventxx::event< ccallback_type >
492  */
493 template < typename F >
494 struct event: basic_event
495 {
496
497         /**
498          * Creates a new event.
499          *
500          * @param fd File descriptor to monitor for events.
501          * @param ev Type of events to monitor (see eventxx::type).
502          * @param handler Callback functor.
503          */
504         event(int fd, short ev, F& handler) throw()
505         {
506                 event_set(this, fd, ev, &wrapper,
507                                 reinterpret_cast< void* >(&handler));
508         }
509
510         protected:
511                 event() {}
512                 static void wrapper(int fd, short ev, void* h)
513                 {
514                         F& handler = *reinterpret_cast< F* >(h);
515                         // Hackish, but this way the handler can get a clean
516                         // event type
517                         handler(fd, *reinterpret_cast< type* >(&ev));
518                 }
519
520 }; // struct event< F >
521
522
523 /**
524  * This is the specialization of eventxx::event for C-style callbacks.
525  *
526  * @see eventxx::event
527  */
528 template <>
529 struct event< ccallback_type >: basic_event
530 {
531
532         /**
533          * Creates a new event.
534          *
535          * @param fd File descriptor to monitor for events.
536          * @param ev Type of events to monitor (see eventxx::type).
537          * @param handler C-style callback function.
538          * @param arg Arbitrary pointer to pass to the handler as argument.
539          */
540         event(int fd, short ev, ccallback_type handler, void* arg) throw()
541         {
542                 event_set(this, fd, ev, handler, arg);
543         }
544
545         protected:
546                 event() {}
547
548 }; // struct event< ccallback_type >
549
550
551 /**
552  * Timer event object.
553  *
554  * This is just a special case of event that is fired only when a timeout is
555  * reached. It's just a shortcut to:
556  * @code
557  * event(-1, 0, handler);
558  * @endcode
559  *
560  * @note This event can't eventxx::PERSIST.
561  * @see timer< ccallback_type >
562  */
563 template < typename F >
564 struct timer: event< F >
565 {
566
567         /**
568          * Creates a new timer event.
569          *
570          * @param handler Callback functor.
571          */
572         timer(F& handler) throw()
573         {
574                 evtimer_set(this, &event< F >::wrapper,
575                         reinterpret_cast< void* >(&handler));
576         }
577
578 }; // struct timer< F >
579
580
581 /**
582  * This is the specialization of eventxx::timer for C-style callbacks.
583  *
584  * @note This event can't eventxx::PERSIST.
585  * @see timer
586  */
587 template <>
588 struct timer< ccallback_type >: event< ccallback_type >
589 {
590
591         /**
592          * Creates a new timer event.
593          *
594          * @param handler C-style callback function.
595          * @param arg Arbitrary pointer to pass to the handler as argument.
596          */
597         timer(ccallback_type handler, void* arg) throw()
598         {
599                 evtimer_set(this, handler, arg);
600         }
601
602 }; // struct timer< ccallback_type >
603
604
605 /**
606  * Signal event object.
607  *
608  * This is just a special case of event that is fired when a signal is raised
609  * (instead of a file descriptor being active). It's just a shortcut to:
610  * @code
611  * event(signum, eventxx::SIGNAL, handler);
612  * @endcode
613  *
614  * @note This event always eventxx::PERSIST.
615  * @see signal< ccallback_type >
616  */
617 template < typename F >
618 struct signal: event< F >
619 {
620
621         /**
622          * Creates a new signal event.
623          *
624          * @param signum Signal number to monitor.
625          * @param handler Callback functor.
626          */
627         signal(int signum, F& handler) throw()
628         {
629                 signal_set(this, signum, &event< F >::wrapper,
630                         reinterpret_cast< void* >(&handler));
631         }
632
633         /**
634          * Event's signal number.
635          *
636          * @return Event's signal number.
637          */
638         int signum() const
639         {
640                 return EVENT_SIGNAL(this);
641         }
642
643 }; // struct signal<F>
644
645
646 /**
647  * This is the specialization of eventxx::signal for C-style callbacks.
648  *
649  * @note This event always eventxx::PERSIST.
650  * @see signal
651  */
652 template <>
653 struct signal< ccallback_type >: event< ccallback_type >
654 {
655
656         /**
657          * Creates a new signal event.
658          *
659          * @param signum Signal number to monitor.
660          * @param handler C-style callback function.
661          * @param arg Arbitrary pointer to pass to the handler as argument.
662          */
663         signal(int signum, ccallback_type handler, void* arg) throw()
664         {
665                 signal_set(this, signum, handler, arg);
666         }
667
668         /**
669          * Event's signal number.
670          *
671          * @return Event's signal number.
672          */
673         int signum() const
674         {
675                 return EVENT_SIGNAL(this);
676         }
677
678 }; // struct signal< ccallback_type >
679
680
681 /// Shortcut to C-style event.
682 typedef eventxx::event< ccallback_type > cevent;
683
684 /// Shortcut to C-style timer.
685 typedef eventxx::timer< ccallback_type > ctimer;
686
687 /// Shortcut to C-style signal handler.
688 typedef eventxx::signal< ccallback_type > csignal;
689
690
691 //@}
692
693
694 /**
695  * Event dispatcher.
696  *
697  * This class is the responsible for looping and dispatching events. Every time
698  * you need an event loop you should create an instance of this class.
699  *
700  * You can @link dispatcher::add add @endlink events to the dispatcher, and you
701  * can @link dispatcher::del remove @endlink them later or you can @link
702  * dispatcher::add_once add events to be processed just once @endlink. You can
703  * @link dispatcher::dispatch loop once or forever @endlink (well, of course you
704  * can break that forever removing all the events or by @link dispatcher::exit
705  * exiting the loop @endlink).
706  */
707 struct dispatcher
708 {
709
710         /**
711          * Creates a default dispatcher (with just 1 priority).
712          *
713          * @see dispatcher(int) if you want to create a dispatcher with more
714          *      priorities.
715          */
716         dispatcher() throw()
717         {
718                 _event_base = static_cast< internal::event_base* >(internal::event_init());
719         }
720
721         /**
722          * Creates a dispatcher with npriorities priorities.
723          *
724          * @param npriorities Number of priority queues to use.
725          */
726         dispatcher(int npriorities) throw(std::bad_alloc)
727         {
728                 _event_base = static_cast< internal::event_base* >(internal::event_init());
729                 if (!_event_base) throw std::bad_alloc();
730                 // Can't fail because there is no way that it has active events
731                 internal::event_base_priority_init(_event_base, npriorities);
732         }
733
734 #ifdef EVENT_BASE_FREE_FIX
735         ~dispatcher() throw() { event_base_free(_event_base); }
736 #else
737 #warning "The dispatcher class *will* leak memory because of a libevent bug, see http://www.mail-archive.com/libevent-users@monkey.org/msg00110.html for more info an a patch. If you already have this patch, please -DEVENT_BASE_FREE_FIX to your compiler to make this message disappear and really free the dispatcher memory using event_base_free()."
738 #endif
739
740         /**
741          * Adds an event to the dispatcher.
742          *
743          * @param e Event to add.
744          * @param priority Priority of the event.
745          */
746         void add(basic_event& e, int priority = DEFAULT_PRIORITY)
747                 throw(invalid_priority)
748         {
749                 internal::event_base_set(_event_base, &e);
750                 if (priority != DEFAULT_PRIORITY
751                                 && internal::event_priority_set(&e, priority))
752                         throw invalid_priority();
753                 internal::event_add(&e, 0);
754         }
755
756         /**
757          * Adds an event to the dispatcher with a timeout.
758          *
759          * The event is fired when there is activity on e or when to has elapsed,
760          * whatever come first.
761          *
762          * @param e Event to add.
763          * @param to Timeout.
764          * @param priority Priority of the event.
765          */
766         void add(basic_event& e, const time& to,
767                         int priority = DEFAULT_PRIORITY)
768                 throw(invalid_priority)
769         {
770                 internal::event_base_set(_event_base, &e);
771                 if (priority != DEFAULT_PRIORITY
772                                 && internal::event_priority_set(&e, priority))
773                         throw invalid_priority();
774                 internal::event_add(&e, const_cast< time* >(&to)); // XXX HACK libevent don't use const
775         }
776
777         /**
778          * Adds a temporary event.
779          *
780          * Adds a temporary event, without the need of instantiating a new event
781          * object. Events added this way can't eventxx::PERSIST.
782          *
783          * @param fd File descriptor to monitor for events.
784          * @param ev Type of events to monitor.
785          * @param handler Callback function.
786          */
787         template < typename F >
788         void add_once(int fd, type ev, F& handler)
789         {
790                 internal::event_once(fd, ev, &dispatcher::wrapper< F >,
791                                 reinterpret_cast< void* >(&handler), 0);
792         }
793
794         /**
795          * Adds a temporary event to with a C-style callback.
796          *
797          * Adds a temporary event, without the need of instantiating a new event
798          * object. Events added this way can't eventxx::PERSIST.
799          *
800          * @param fd File descriptor to monitor for events.
801          * @param ev Type of events to monitor.
802          * @param handler Callback function.
803          * @param arg Arbitrary pointer to pass to the handler as argument.
804          */
805         void add_once(int fd, type ev, ccallback_type handler, void* arg)
806         {
807                 internal::event_once(fd, ev, handler, arg, 0);
808         }
809
810         /**
811          * Adds a temporary event.
812          *
813          * Adds a temporary event, without the need of instantiating a new event
814          * object. Events added this way can't eventxx::PERSIST.
815          *
816          * @param fd File descriptor to monitor for events.
817          * @param ev Type of events to monitor.
818          * @param handler Callback function.
819          * @param to Timeout.
820          */
821         template < typename F >
822         void add_once(int fd, type ev, F& handler, const time& to)
823         {
824                 internal::event_once(fd, ev, &dispatcher::wrapper< F >,
825                                 reinterpret_cast< void* >(&handler),
826                                 const_cast< time* >(&to)); // XXX HACK libevent don't use const
827         }
828
829         /**
830          * Adds a temporary event with a C-style callback.
831          *
832          * Adds a temporary event, without the need of instantiating a new event
833          * object. Events added this way can't eventxx::PERSIST.
834          *
835          * @param fd File descriptor to monitor for events.
836          * @param ev Type of events to monitor.
837          * @param handler Callback function.
838          * @param arg Arbitrary pointer to pass to the handler as argument.
839          * @param to Timeout.
840          */
841         void add_once(int fd, type ev, ccallback_type handler, void* arg, const time& to)
842         {
843                 internal::event_once(fd, ev, handler, arg, const_cast< time* >(&to)); // XXX HACK libevent don't use const
844         }
845
846         /**
847          * Adds a temporary timer.
848          *
849          * Adds a temporary timer, without the need of instantiating a new timer
850          * object.
851          *
852          * @param handler Callback function.
853          * @param to Timer's timeout.
854          */
855         template < typename F >
856         void add_once_timer(F& handler, const time& to)
857         {
858                 internal::event_once(-1, EV_TIMEOUT, &dispatcher::wrapper< F >,
859                                 reinterpret_cast< void* >(&handler),
860                                 const_cast< time* >(&to)); // XXX HACK libevent don't use const
861         }
862
863         /**
864          * Adds a temporary timer with a C-style callback.
865          *
866          * Adds a temporary timer, without the need of instantiating a new timer
867          * object.
868          *
869          * @param handler Callback function.
870          * @param arg Arbitrary pointer to pass to the handler as argument.
871          * @param to Timer's timeout.
872          */
873         void add_once_timer(ccallback_type handler, void* arg, const time& to)
874         {
875                 internal::event_once(-1, EV_TIMEOUT, handler, arg, const_cast< time* >(&to)); // XXX HACK libevent don't use const
876         }
877
878         /**
879          * Removes an event.
880          *
881          * The event e will be no longer monitored by this dispatcher.
882          *
883          * @param e Event to remove.
884          */
885         void del(basic_event& e) throw()
886         {
887                 internal::event_del(&e);
888         }
889
890         /**
891          * Main dispatcher loop.
892          *
893          * This function takes the control of the program, waiting for an event
894          * and calling its callbacks when it's fired. It only returns under
895          * this conditions:
896          * - exit() was called.
897          * - All events were del()eted.
898          * - Another internal error.
899          * - eventxx::ONCE flag was set.
900          * - eventxx::NONBLOCK flag was set.
901          *
902          * @param flags If eventxx::ONCE is specified, then just one event is
903          *              processed, if eventxx::NONBLOCK is specified, then this
904          *              function returns even if there are no pending events.
905          */
906         int dispatch(int flags = 0) // TODO  throw(exception)
907         {
908                 return internal::event_base_loop(_event_base, flags);
909         }
910
911         /**
912          * Exit the dispatch() loop.
913          *
914          * @param to If a timeout is given, the loop exits after the specified
915          *           time is elapsed.
916          */
917         int exit(const time& to = time())
918         {
919                 // XXX HACK libevent don't use const
920                 return internal::event_base_loopexit(_event_base,
921                         const_cast< time* >(&to));
922         }
923
924         protected:
925                 internal::event_base* _event_base;
926                 template < typename F >
927                 static void wrapper(int fd, type ev, void* h)
928                 {
929                         F& handler = *reinterpret_cast< F* >(h);
930                         handler(fd, *reinterpret_cast< type* >(&ev));
931                 }
932
933 }; // struct dispatcher
934
935
936 } // namespace event
937
938 #endif // _EVENTXX_HPP_
939
940 // vim: set filetype=cpp :