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