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