]> git.llucax.com Git - software/eventxx.git/blob - eventxx
66e94ea69ecd8e4f9ebf9545e633a95e0a0e9933
[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.
200  */
201
202 /** @example test-weof.cpp
203  *
204  * This is some kind of test of EOF ported from libevent.
205  */
206
207 /** @example trivial.cpp
208  *
209  * This is the most trivial example.
210  */
211
212 /**
213  * Namespace for all symbols libevent C++ wrapper defines.
214  */
215 namespace eventxx
216 {
217
218
219 // All libevent C API symbols and other internal stuff goes here.
220 namespace internal
221 {
222 #include <event.h>
223 }
224
225
226 /** @defgroup exceptions Exceptions
227  *
228  * eventxx makes a heavy use of exceptions. Each function has it's exceptions
229  * specified, so it's very easy to find out what exceptions to expect.
230  *
231  * Exceptions are mostly thrown when there is a programming error. So if you get
232  * an exception check your code.
233  */
234 //@{
235
236
237 /**
238  * Base class for all libevent exceptions.
239  */
240 struct exception: public std::exception
241 {
242 };
243
244
245 /**
246  * Invalid event exception.
247  *
248  * This exception is thrown when passing an invalid event to a function, the
249  * reason is given in the what() description but it usually means that the you
250  * are making some restricted operation with an active event.
251  *
252  * If you hit this exception, you probably got a programming error.
253  */
254 struct invalid_event: public std::invalid_argument, public exception
255 {
256
257         /**
258          * Creates an invalid event exception with a reason.
259          *
260          * @param what Reason why the event is invalid).
261          */
262         explicit invalid_event(const std::string& what) throw():
263                 std::invalid_argument(what)
264         {
265         }
266
267 }; // struct invalid_event
268
269
270 /**
271  * Invalid priority exception.
272  *
273  * This exception is thrown when passing an invalid priority to a function. This
274  * usually means you don't have enough priority queues in your dispatcher, so
275  * you should have allocated more in the constructor.
276  *
277  * If you hit this exception, you probably got a programming error.
278  *
279  * @see dispatcher::dispatcher(int) to allocate more priority queues.
280  */
281 struct invalid_priority: public std::invalid_argument, public exception
282 {
283
284         /**
285          * Creates an invalid priority exception with a reason.
286          *
287          * @param what Reason why the priority is invalid).
288          */
289         explicit invalid_priority(const std::string& what
290                         = "invalid priority value") throw():
291                 std::invalid_argument(what)
292         {
293         }
294
295 }; // struct invalid_priority
296
297 //@}
298
299
300 /// Miscellaneous constants
301 enum
302 {
303         DEFAULT_PRIORITY = -1,      ///< Default priority (the middle value).
304         ONCE = EVLOOP_ONCE,         ///< Loop just once.
305         NONBLOCK = EVLOOP_NONBLOCK  ///< Don't block the event loop.
306 };
307
308
309 /// C function used as callback in the C API.
310 typedef void (*ccallback_type)(int, short, void*);
311
312
313 /**
314  * Time used for timeout values.
315  *
316  * This timeout is compose of seconds and microseconds.
317  */
318 struct time: ::timeval
319 {
320
321         /**
322          * Creates a new time with @p sec seconds and @p usec microseconds.
323          *
324          * @param sec Number of seconds.
325          * @param usec Number of microseconds.
326          */
327         time(long sec = 0l, long usec = 0l) throw()
328                 { tv_sec = sec; tv_usec = usec; }
329
330         /**
331          * Gets the number of seconds.
332          *
333          * @return Number of seconds.
334          */
335         long sec() const throw() { return tv_sec; };
336
337         /**
338          * Gets the number of microseconds.
339          *
340          * @return Number of microseconds.
341          */
342         long usec() const throw() { return tv_usec; };
343
344         /**
345          * Sets the number of seconds.
346          *
347          * @param s Number of seconds.
348          */
349         void sec(long s) throw() { tv_sec = s; };
350
351         /**
352          * Sets the number of microseconds.
353          *
354          * @param u Number of microseconds.
355          */
356         void usec(long u) throw() { tv_usec = u; };
357
358 }; // struct time
359
360
361 /** @defgroup events Events
362  *
363  * There are many ways to specify how to handle an event. You can use use the
364  * same plain functions callbacks (see eventxx::cevent, eventxx::ctimer and
365  * eventxx::csignal) like in C or the other kind of more advanced, stateful
366  * function objects (see eventxx::event, eventxx::timer and eventxx::signal
367  * templates). The former are just typedef'ed specialization of the later.
368  *
369  * All events derive from a plain class (not template) eventxx::basic_event, one
370  * of the main utilities of it (besides containing common code ;) is to be used
371  * in STL containers.
372  *
373  * Please see each class documentation for details and examples.
374  */
375 //@{
376
377 /**
378  * Type of events.
379  *
380  * There are 4 kind of events: eventxx::TIMEOUT, eventxx::READ, eventxx::WRITE
381  * or eventxx::SIGNAL. eventxx::PERSIST is not an event, is an event modifier
382  * flag, that tells eventxx that this event should live until dispatcher::del()
383  * is called. You can use, for example:
384  * @code
385  * eventxx::event(fd, eventxx::READ | eventxx::PERSIST, ...);
386  * @endcode
387  */
388 enum type
389 {
390         TIMEOUT = EV_TIMEOUT, ///< Timeout event.
391         READ = EV_READ,       ///< Read event.
392         WRITE = EV_WRITE,     ///< Write event.
393         SIGNAL = EV_SIGNAL,   ///< Signal event.
394         PERSIST = EV_PERSIST  ///< Not really an event, is an event modifier.
395 };
396
397 /**
398  * Basic event from which all events derive.
399  *
400  * All events derive from this class, so it's useful for use in containers,
401  * like:
402  * @code
403  * std::list< eventxx::basic_event* > events;
404  * @endcode
405  */
406 struct basic_event: internal::event
407 {
408
409         /**
410          * Checks if there is an event pending.
411          *
412          * @param ev Type of event to check.
413          *
414          * @return true if there is a pending event, false if not.
415          */
416         bool pending(type ev) const throw()
417         {
418                 // HACK libevent don't use const
419                 return event_pending(const_cast< basic_event* >(this), ev, 0);
420         }
421
422         /**
423          * Timeout of the event.
424          *
425          * @return Timeout of the event.
426          */
427         time timeout() const throw()
428         {
429                 time tv;
430                 // HACK libevent don't use const
431                 event_pending(const_cast< basic_event* >(this), EV_TIMEOUT, &tv);
432                 return tv;
433         }
434
435         /**
436          * Sets the event's priority.
437          *
438          * @param priority New event priority.
439          *
440          * @pre The event must be added to some dispatcher.
441          *
442          * @see dispatcher::dispatcher(int)
443          */
444         void priority(int priority) const throw(invalid_event, invalid_priority)
445         {
446                 if (ev_flags & EVLIST_ACTIVE)
447                         throw invalid_event("can't change the priority of an "
448                                         "active event");
449                 // HACK libevent don't use const
450                 if (event_priority_set(const_cast< basic_event* >(this),
451                                         priority))
452                         throw invalid_priority();
453         }
454
455         /**
456          * Event's file descriptor.
457          *
458          * @return Event's file descriptor.
459          */
460         int fd() const throw()
461         {
462                 return EVENT_FD(this);
463         }
464
465         /// @note This is an abstract class, you can't instantiate it.
466         protected:
467                 basic_event() throw() {}
468                 basic_event(const basic_event&);
469                 basic_event& operator= (const basic_event&);
470
471 }; // struct basic_event
472
473
474 /**
475  * Generic event object.
476  *
477  * This object stores all the information about an event, including a callback
478  * functor, which is called when the event is fired. The template parameter
479  * must be a functor (callable object or function) that can take 2 parameters:
480  * an integer (the file descriptor of the fired event) and an event::type (the
481  * type of event being fired).
482  * There is a specialized version of this class which takes as the template
483  * parameter a C function with the ccallback_type signature, just like C
484  * libevent API does.
485  *
486  * @see eventxx::event< ccallback_type >
487  */
488 template < typename F >
489 struct event: basic_event
490 {
491
492         /**
493          * Creates a new event.
494          *
495          * @param fd File descriptor to monitor for events.
496          * @param ev Type of events to monitor (see eventxx::type).
497          * @param handler Callback functor.
498          */
499         event(int fd, short ev, F& handler) throw()
500         {
501                 event_set(this, fd, ev, &wrapper,
502                                 reinterpret_cast< void* >(&handler));
503         }
504
505         protected:
506                 event() {}
507                 static void wrapper(int fd, short ev, void* h)
508                 {
509                         F& handler = *reinterpret_cast< F* >(h);
510                         // Hackish, but this way the handler can get a clean
511                         // event type
512                         handler(fd, *reinterpret_cast< type* >(&ev));
513                 }
514
515 }; // struct event< F >
516
517
518 /**
519  * This is the specialization of eventxx::event for C-style callbacks.
520  *
521  * @see eventxx::event
522  */
523 template <>
524 struct event< ccallback_type >: basic_event
525 {
526
527         /**
528          * Creates a new event.
529          *
530          * @param fd File descriptor to monitor for events.
531          * @param ev Type of events to monitor (see eventxx::type).
532          * @param handler C-style callback function.
533          * @param arg Arbitrary pointer to pass to the handler as argument.
534          */
535         event(int fd, short ev, ccallback_type handler, void* arg) throw()
536         {
537                 event_set(this, fd, ev, handler, arg);
538         }
539
540         protected:
541                 event() {}
542
543 }; // struct event< ccallback_type >
544
545
546 /**
547  * Timer event object.
548  *
549  * This is just a special case of event that is fired only when a timeout is
550  * reached. It's just a shortcut to:
551  * @code
552  * event(-1, 0, handler);
553  * @endcode
554  *
555  * @note This event can't eventxx::PERSIST.
556  * @see timer< ccallback_type >
557  */
558 template < typename F >
559 struct timer: event< F >
560 {
561
562         /**
563          * Creates a new timer event.
564          *
565          * @param handler Callback functor.
566          */
567         timer(F& handler) throw()
568         {
569                 evtimer_set(this, &event< F >::wrapper,
570                         reinterpret_cast< void* >(&handler));
571         }
572
573 }; // struct timer< F >
574
575
576 /**
577  * This is the specialization of eventxx::timer for C-style callbacks.
578  *
579  * @note This event can't eventxx::PERSIST.
580  * @see timer
581  */
582 template <>
583 struct timer< ccallback_type >: event< ccallback_type >
584 {
585
586         /**
587          * Creates a new timer event.
588          *
589          * @param handler C-style callback function.
590          * @param arg Arbitrary pointer to pass to the handler as argument.
591          */
592         timer(ccallback_type handler, void* arg) throw()
593         {
594                 evtimer_set(this, handler, arg);
595         }
596
597 }; // struct timer< ccallback_type >
598
599
600 /**
601  * Signal event object.
602  *
603  * This is just a special case of event that is fired when a signal is raised
604  * (instead of a file descriptor being active). It's just a shortcut to:
605  * @code
606  * event(signum, eventxx::SIGNAL, handler);
607  * @endcode
608  *
609  * @note This event always eventxx::PERSIST.
610  * @see signal< ccallback_type >
611  */
612 template < typename F >
613 struct signal: event< F >
614 {
615
616         /**
617          * Creates a new signal event.
618          *
619          * @param signum Signal number to monitor.
620          * @param handler Callback functor.
621          */
622         signal(int signum, F& handler) throw()
623         {
624                 signal_set(this, signum, &event< F >::wrapper,
625                         reinterpret_cast< void* >(&handler));
626         }
627
628         /**
629          * Event's signal number.
630          *
631          * @return Event's signal number.
632          */
633         int signum() const
634         {
635                 return EVENT_SIGNAL(this);
636         }
637
638 }; // struct signal<F>
639
640
641 /**
642  * This is the specialization of eventxx::signal for C-style callbacks.
643  *
644  * @note This event always eventxx::PERSIST.
645  * @see signal
646  */
647 template <>
648 struct signal< ccallback_type >: event< ccallback_type >
649 {
650
651         /**
652          * Creates a new signal event.
653          *
654          * @param signum Signal number to monitor.
655          * @param handler C-style callback function.
656          * @param arg Arbitrary pointer to pass to the handler as argument.
657          */
658         signal(int signum, ccallback_type handler, void* arg) throw()
659         {
660                 signal_set(this, signum, handler, arg);
661         }
662
663         /**
664          * Event's signal number.
665          *
666          * @return Event's signal number.
667          */
668         int signum() const
669         {
670                 return EVENT_SIGNAL(this);
671         }
672
673 }; // struct signal< ccallback_type >
674
675
676 /// Shortcut to C-style event.
677 typedef eventxx::event< ccallback_type > cevent;
678
679 /// Shortcut to C-style timer.
680 typedef eventxx::timer< ccallback_type > ctimer;
681
682 /// Shortcut to C-style signal handler.
683 typedef eventxx::signal< ccallback_type > csignal;
684
685
686 //@}
687
688
689 /**
690  * Event dispatcher.
691  *
692  * This class is the responsible for looping and dispatching events. Every time
693  * you need an event loop you should create an instance of this class.
694  *
695  * You can @link dispatcher::add add @endlink events to the dispatcher, and you
696  * can @link dispatcher::del remove @endlink them later or you can @link
697  * dispatcher::add_once add events to be processed just once @endlink. You can
698  * @link dispatcher::dispatch loop once or forever @endlink (well, of course you
699  * can break that forever removing all the events or by @link dispatcher::exit
700  * exiting the loop @endlink).
701  */
702 struct dispatcher
703 {
704
705         /**
706          * Creates a default dispatcher (with just 1 priority).
707          *
708          * @see dispatcher(int) if you want to create a dispatcher with more
709          *      priorities.
710          */
711         dispatcher() throw()
712         {
713                 _event_base = static_cast< internal::event_base* >(internal::event_init());
714         }
715
716         /**
717          * Creates a dispatcher with npriorities priorities.
718          *
719          * @param npriorities Number of priority queues to use.
720          */
721         dispatcher(int npriorities) throw(std::bad_alloc)
722         {
723                 _event_base = static_cast< internal::event_base* >(internal::event_init());
724                 if (!_event_base) throw std::bad_alloc();
725                 // Can't fail because there is no way that it has active events
726                 internal::event_base_priority_init(_event_base, npriorities);
727         }
728
729 #ifdef EVENT_BASE_FREE_FIX
730         ~dispatcher() throw() { event_base_free(_event_base); }
731 #else
732 #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()."
733 #endif
734
735         /**
736          * Adds an event to the dispatcher.
737          *
738          * @param e Event to add.
739          * @param priority Priority of the event.
740          */
741         void add(basic_event& e, int priority = DEFAULT_PRIORITY)
742                 throw(invalid_priority)
743         {
744                 internal::event_base_set(_event_base, &e);
745                 if (priority != DEFAULT_PRIORITY
746                                 && internal::event_priority_set(&e, priority))
747                         throw invalid_priority();
748                 internal::event_add(&e, 0);
749         }
750
751         /**
752          * Adds an event to the dispatcher with a timeout.
753          *
754          * The event is fired when there is activity on e or when to has elapsed,
755          * whatever come first.
756          *
757          * @param e Event to add.
758          * @param to Timeout.
759          * @param priority Priority of the event.
760          */
761         void add(basic_event& e, const time& to,
762                         int priority = DEFAULT_PRIORITY)
763                 throw(invalid_priority)
764         {
765                 internal::event_base_set(_event_base, &e);
766                 if (priority != DEFAULT_PRIORITY
767                                 && internal::event_priority_set(&e, priority))
768                         throw invalid_priority();
769                 internal::event_add(&e, const_cast< time* >(&to)); // XXX HACK libevent don't use const
770         }
771
772         /**
773          * Adds a temporary event.
774          *
775          * Adds a temporary event, without the need of instantiating a new event
776          * object. Events added this way can't eventxx::PERSIST.
777          *
778          * @param fd File descriptor to monitor for events.
779          * @param ev Type of events to monitor.
780          * @param handler Callback function.
781          */
782         template < typename F >
783         void add_once(int fd, type ev, F& handler)
784         {
785                 internal::event_once(fd, ev, &dispatcher::wrapper< F >,
786                                 reinterpret_cast< void* >(&handler), 0);
787         }
788
789         /**
790          * Adds a temporary event to with a C-style callback.
791          *
792          * Adds a temporary event, without the need of instantiating a new event
793          * object. Events added this way can't eventxx::PERSIST.
794          *
795          * @param fd File descriptor to monitor for events.
796          * @param ev Type of events to monitor.
797          * @param handler Callback function.
798          * @param arg Arbitrary pointer to pass to the handler as argument.
799          */
800         void add_once(int fd, type ev, ccallback_type handler, void* arg)
801         {
802                 internal::event_once(fd, ev, handler, arg, 0);
803         }
804
805         /**
806          * Adds a temporary event.
807          *
808          * Adds a temporary event, without the need of instantiating a new event
809          * object. Events added this way can't eventxx::PERSIST.
810          *
811          * @param fd File descriptor to monitor for events.
812          * @param ev Type of events to monitor.
813          * @param handler Callback function.
814          * @param to Timeout.
815          */
816         template < typename F >
817         void add_once(int fd, type ev, F& handler, const time& to)
818         {
819                 internal::event_once(fd, ev, &dispatcher::wrapper< F >,
820                                 reinterpret_cast< void* >(&handler),
821                                 const_cast< time* >(&to)); // XXX HACK libevent don't use const
822         }
823
824         /**
825          * Adds a temporary event with a C-style callback.
826          *
827          * Adds a temporary event, without the need of instantiating a new event
828          * object. Events added this way can't eventxx::PERSIST.
829          *
830          * @param fd File descriptor to monitor for events.
831          * @param ev Type of events to monitor.
832          * @param handler Callback function.
833          * @param arg Arbitrary pointer to pass to the handler as argument.
834          * @param to Timeout.
835          */
836         void add_once(int fd, type ev, ccallback_type handler, void* arg, const time& to)
837         {
838                 internal::event_once(fd, ev, handler, arg, const_cast< time* >(&to)); // XXX HACK libevent don't use const
839         }
840
841         /**
842          * Adds a temporary timer.
843          *
844          * Adds a temporary timer, without the need of instantiating a new timer
845          * object.
846          *
847          * @param handler Callback function.
848          * @param to Timer's timeout.
849          */
850         template < typename F >
851         void add_once_timer(F& handler, const time& to)
852         {
853                 internal::event_once(-1, EV_TIMEOUT, &dispatcher::wrapper< F >,
854                                 reinterpret_cast< void* >(&handler),
855                                 const_cast< time* >(&to)); // XXX HACK libevent don't use const
856         }
857
858         /**
859          * Adds a temporary timer with a C-style callback.
860          *
861          * Adds a temporary timer, without the need of instantiating a new timer
862          * object.
863          *
864          * @param handler Callback function.
865          * @param arg Arbitrary pointer to pass to the handler as argument.
866          * @param to Timer's timeout.
867          */
868         void add_once_timer(ccallback_type handler, void* arg, const time& to)
869         {
870                 internal::event_once(-1, EV_TIMEOUT, handler, arg, const_cast< time* >(&to)); // XXX HACK libevent don't use const
871         }
872
873         /**
874          * Removes an event.
875          *
876          * The event e will be no longer monitored by this dispatcher.
877          *
878          * @param e Event to remove.
879          */
880         void del(basic_event& e) throw()
881         {
882                 internal::event_del(&e);
883         }
884
885         /**
886          * Main dispatcher loop.
887          *
888          * This function takes the control of the program, waiting for an event
889          * and calling its callbacks when it's fired. It only returns under
890          * this conditions:
891          * - exit() was called.
892          * - All events were del()eted.
893          * - Another internal error.
894          * - eventxx::ONCE flag was set.
895          * - eventxx::NONBLOCK flag was set.
896          *
897          * @param flags If eventxx::ONCE is specified, then just one event is
898          *              processed, if eventxx::NONBLOCK is specified, then this
899          *              function returns even if there are no pending events.
900          */
901         int dispatch(int flags = 0) // TODO  throw(exception)
902         {
903                 return internal::event_base_loop(_event_base, flags);
904         }
905
906         /**
907          * Exit the dispatch() loop.
908          *
909          * @param to If a timeout is given, the loop exits after the specified
910          *           time is elapsed.
911          */
912         int exit(const time& to = time())
913         {
914                 // XXX HACK libevent don't use const
915                 return internal::event_base_loopexit(_event_base,
916                         const_cast< time* >(&to));
917         }
918
919         protected:
920                 internal::event_base* _event_base;
921                 template < typename F >
922                 static void wrapper(int fd, type ev, void* h)
923                 {
924                         F& handler = *reinterpret_cast< F* >(h);
925                         handler(fd, *reinterpret_cast< type* >(&ev));
926                 }
927
928 }; // struct dispatcher
929
930
931 } // namespace event
932
933 #endif // _EVENTXX_HPP_
934
935 // vim: set filetype=cpp :