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