]> git.llucax.com Git - software/libev.git/blob - ev++.h
a7d99c0ccf3241c30e4b7f19de83cf5c2cc5a6e7
[software/libev.git] / ev++.h
1 /*
2  * libev simple C++ wrapper classes
3  *
4  * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modifica-
8  * tion, are permitted provided that the following conditions are met:
9  * 
10  *   1.  Redistributions of source code must retain the above copyright notice,
11  *       this list of conditions and the following disclaimer.
12  * 
13  *   2.  Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in the
15  *       documentation and/or other materials provided with the distribution.
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21  * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25  * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26  * OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Alternatively, the contents of this file may be used under the terms of
29  * the GNU General Public License ("GPL") version 2 or any later version,
30  * in which case the provisions of the GPL are applicable instead of
31  * the above. If you wish to allow the use of your version of this file
32  * only under the terms of the GPL and not to allow others to use your
33  * version of this file under the BSD license, indicate your decision
34  * by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL. If you do not delete the
36  * provisions above, a recipient may use your version of this file under
37  * either the BSD or the GPL.
38  */
39
40 #ifndef EVPP_H__
41 #define EVPP_H__
42
43 #ifdef EV_H
44 # include EV_H
45 #else
46 # include "ev.h"
47 #endif
48
49 #ifndef EV_CXX_EXCEPTIONS
50 #define EV_CXX_EXCEPTIONS 1
51 #endif
52
53 #undef EV_THROW
54 #if EV_CXX_EXCEPTIONS
55 #  include <stdexcept>
56 #  define EV_THROW(exception) throw (exception)
57 #else
58 #  define EV_THROW(exception)
59 #endif
60
61 namespace ev {
62
63   typedef ev_tstamp tstamp;
64
65   enum {
66     UNDEF    = EV_UNDEF,
67     NONE     = EV_NONE,
68     READ     = EV_READ,
69     WRITE    = EV_WRITE,
70     TIMEOUT  = EV_TIMEOUT,
71     PERIODIC = EV_PERIODIC,
72     SIGNAL   = EV_SIGNAL,
73     CHILD    = EV_CHILD,
74     STAT     = EV_STAT,
75     IDLE     = EV_IDLE,
76     CHECK    = EV_CHECK,
77     PREPARE  = EV_PREPARE,
78     FORK     = EV_FORK,
79     EMBED    = EV_EMBED,
80     ERROR    = EV_ERROR,
81   };
82
83   enum
84   {
85     AUTO = EVFLAG_AUTO,
86     NOENV = EVFLAG_NOENV,
87     FORKCHECK = EVFLAG_FORKCHECK,
88     SELECT = EVBACKEND_SELECT,
89     POLL = EVBACKEND_POLL,
90     EPOLL = EVBACKEND_EPOLL,
91     KQUEUE = EVBACKEND_KQUEUE,
92     DEVPOLL = EVBACKEND_DEVPOLL,
93     PORT = EVBACKEND_PORT
94   };
95
96   enum
97   {
98     NONBLOCK = EVLOOP_NONBLOCK,
99     ONESHOT = EVLOOP_ONESHOT
100   };
101
102   enum how_t
103   {
104     ONE = EVUNLOOP_ONE,
105     ALL = EVUNLOOP_ALL
106   };
107
108 #if EV_CXX_EXCEPTIONS
109   struct bad_loop : std::runtime_error
110   {
111     bad_loop ()
112     : std::runtime_error ("loop can't be initialized")
113     {
114     }
115   };
116 #endif
117
118 #ifdef EV_AX
119 #  undef EV_AX
120 #endif
121
122 #ifdef EV_AX_
123 #  undef EV_AX_
124 #endif
125
126 #if EV_MULTIPLICITY
127 #  define EV_AX  raw_loop
128 #  define EV_AX_ raw_loop,
129 #else
130 #  define EV_AX
131 #  define EV_AX_
132 #endif
133
134   struct loop_ref
135   {
136
137     loop_ref (EV_P)
138 #if EV_MULTIPLICITY
139       EV_THROW (bad_loop) : EV_AX (EV_A)
140 #endif
141     {
142 #if EV_MULTIPLICIY && EV_CXX_EXCEPTIONS
143       if (!EV_A)
144         throw bad_loop ();
145 #endif
146     }
147
148     bool operator== (const loop_ref &other) const throw ()
149     {
150 #if EV_MULTIPLICITY
151       return this->EV_AX == other.EV_AX;
152 #else
153       return true;
154 #endif
155     }
156
157     bool operator!= (const loop_ref &other) const throw ()
158     {
159 #if EV_MULTIPLICITY
160       return ! (*this == other);
161 #else
162       return false;
163 #endif
164     }
165
166 #if EV_MULTIPLICITY
167     bool operator== (struct ev_loop *other) const throw ()
168     {
169       return this->EV_AX == other;
170     }
171
172     bool operator!= (struct ev_loop *other) const throw ()
173     {
174       return ! (*this == other);
175     }
176
177     bool operator== (const struct ev_loop *other) const throw ()
178     {
179       return this->EV_AX == other;
180     }
181
182     bool operator!= (const struct ev_loop *other) const throw ()
183     {
184       return (*this == other);
185     }
186
187     operator struct ev_loop * () const throw ()
188     {
189       return EV_AX;
190     }
191
192     operator const struct ev_loop * () const throw ()
193     {
194       return EV_AX;
195     }
196
197     bool is_default () const throw ()
198     {
199       return EV_AX == ev_default_loop (0);
200     }
201 #endif
202
203     void loop (int flags = 0)
204     {
205       ev_loop (EV_AX_ flags);
206     }
207
208     void unloop (how_t how = ONE) throw ()
209     {
210       ev_unloop (EV_AX_ how);
211     }
212
213     void post_fork () throw ()
214     {
215 #if EV_MULTIPLICITY
216       ev_loop_fork (EV_AX);
217 #else
218       ev_default_fork ();
219 #endif
220     }
221
222     unsigned int count () const throw ()
223     {
224       return ev_loop_count (EV_AX);
225     }
226
227     unsigned int backend () const throw ()
228     {
229       return ev_backend (EV_AX);
230     }
231
232     tstamp now () const throw ()
233     {
234       return ev_now (EV_AX);
235     }
236
237     void ref () throw ()
238     {
239       ev_ref (EV_AX);
240     }
241
242     void unref () throw ()
243     {
244       ev_unref (EV_AX);
245     }
246
247     void set_io_collect_interval (tstamp interval) throw ()
248     {
249       ev_set_io_collect_interval (EV_AX_ interval);
250     }
251
252     void set_timeout_collect_interval (tstamp interval) throw ()
253     {
254       ev_set_timeout_collect_interval (EV_AX_ interval);
255     }
256
257     // function callback
258     void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void* arg = 0) throw ()
259     {
260       ev_once (EV_AX_ fd, events, timeout, cb, arg);
261     }
262
263     // method callback
264     template<class K, void (K::*method)(int)>
265     void once (int fd, int events, tstamp timeout, K *object) throw ()
266     {
267       once (fd, events, timeout, method_thunk<K, method>, object);
268     }
269
270     template<class K, void (K::*method)(int)>
271     static void method_thunk (int revents, void* arg)
272     {
273       K *obj = static_cast<K *>(arg);
274       (obj->*method) (revents);
275     }
276
277     // const method callback
278     template<class K, void (K::*method)(int) const>
279     void once (int fd, int events, tstamp timeout, const K *object) throw ()
280     {
281       once (fd, events, timeout, const_method_thunk<K, method>, object);
282     }
283
284     template<class K, void (K::*method)(int) const>
285     static void const_method_thunk (int revents, void* arg)
286     {
287       K *obj = static_cast<K *>(arg);
288       (obj->*method) (revents);
289     }
290
291     // simple method callback
292     template<class K, void (K::*method)()>
293     void once (int fd, int events, tstamp timeout, K *object) throw ()
294     {
295       once (fd, events, timeout, method_noargs_thunk<K, method>, object);
296     }
297
298     template<class K, void (K::*method)()>
299     static void method_noargs_thunk (int revents, void* arg)
300     {
301       K *obj = static_cast<K *>(arg);
302       (obj->*method) ();
303     }
304
305     // simpler function callback
306     template<void (*cb)(int)>
307     void once (int fd, int events, tstamp timeout) throw ()
308     {
309       once (fd, events, timeout, simpler_func_thunk<cb>);
310     }
311
312     template<void (*cb)(int)>
313     static void simpler_func_thunk (int revents, void* arg)
314     {
315       (*cb) (revents);
316     }
317
318     // simplest function callback
319     template<void (*cb)()>
320     void once (int fd, int events, tstamp timeout) throw ()
321     {
322       once (fd, events, timeout, simplest_func_thunk<cb>);
323     }
324
325     template<void (*cb)()>
326     static void simplest_func_thunk (int revents, void* arg)
327     {
328       (*cb) ();
329     }
330
331     void feed_fd_event (int fd, int revents) throw ()
332     {
333       ev_feed_fd_event (EV_AX_ fd, revents);
334     }
335
336     void feed_signal_event (int signum) throw ()
337     {
338       ev_feed_signal_event (EV_AX_ signum);
339     }
340
341 #if EV_MULTIPLICITY
342     struct ev_loop* EV_AX;
343 #endif
344
345   };
346
347 #if EV_MULTIPLICITY
348   struct dynamic_loop: loop_ref
349   {
350
351     dynamic_loop (unsigned int flags = AUTO) EV_THROW (bad_loop)
352       : loop_ref (ev_loop_new (flags))
353     {
354     }
355
356     ~dynamic_loop () throw ()
357     {
358       ev_loop_destroy (EV_AX);
359       EV_AX = 0;
360     }
361
362   private:
363
364     dynamic_loop (const dynamic_loop &);
365
366     dynamic_loop & operator= (const dynamic_loop &);
367
368   };
369 #endif
370
371   struct default_loop: loop_ref
372   {
373
374     default_loop (unsigned int flags = AUTO) EV_THROW (bad_loop)
375 #if EV_MULTIPLICITY
376       : loop_ref (ev_default_loop (flags))
377     {
378     }
379 #else
380     {
381     #if EV_CXX_EXCEPTIONS
382       int r =
383     #endif
384           ev_default_loop (flags);
385     #if EV_CXX_EXCEPTIONS
386       if (!r)
387         throw bad_loop ();
388     #endif
389     }
390 #endif
391
392     ~default_loop () throw ()
393     {
394       ev_default_destroy ();
395 #if EV_MULTIPLICITY
396       EV_AX = 0;
397 #endif
398     }
399
400   private:
401
402     default_loop (const default_loop &);
403
404     default_loop & operator= (const default_loop &);
405
406   };
407
408   inline loop_ref get_default_loop () throw ()
409   {
410 #if EV_MULTIPLICITY
411     return ev_default_loop (0);
412 #else
413     return loop_ref ();
414 #endif
415   }
416
417 #undef EV_AX
418 #undef EV_AX_
419
420 #undef EV_PX
421 #undef EV_PX_
422 #if EV_MULTIPLICITY
423 #  define EV_PX  loop_ref EV_A
424 #  define EV_PX_ loop_ref EV_A_
425 #else
426 #  define EV_PX
427 #  define EV_PX_
428 #endif
429
430   template<class ev_watcher, class watcher>
431   struct base : ev_watcher
432   {
433     #if EV_MULTIPLICITY
434       EV_PX;
435
436       void set (EV_PX) throw ()
437       {
438         this->EV_A = EV_A;
439       }
440     #endif
441
442     base (EV_PX) throw ()
443     #if EV_MULTIPLICITY
444       : EV_A (EV_A)
445     #endif
446     {
447       ev_init (this, 0);
448     }
449
450     void set_ (void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) throw ()
451     {
452       this->data = data;
453       ev_set_cb (static_cast<ev_watcher *>(this), cb);
454     }
455
456     // method callback
457     template<class K, void (K::*method)(watcher &w, int)>
458     void set (K *object) throw ()
459     {
460       set_ (object, method_thunk<K, method>);
461     }
462
463     template<class K, void (K::*method)(watcher &w, int)>
464     static void method_thunk (EV_P_ ev_watcher *w, int revents)
465     {
466       K *obj = static_cast<K *>(w->data);
467       (obj->*method) (*static_cast<watcher *>(w), revents);
468     }
469
470     // const method callback
471     template<class K, void (K::*method)(watcher &w, int) const>
472     void set (const K *object) throw ()
473     {
474       set_ (object, const_method_thunk<K, method>);
475     }
476
477     template<class K, void (K::*method)(watcher &w, int) const>
478     static void const_method_thunk (EV_P_ ev_watcher *w, int revents)
479     {
480       K *obj = static_cast<K *>(w->data);
481       (static_cast<K *>(w->data)->*method) (*static_cast<watcher *>(w), revents);
482     }
483
484     // function callback
485     template<void (*function)(watcher &w, int)>
486     void set (void *data = 0) throw ()
487     {
488       set_ (data, function_thunk<function>);
489     }
490
491     template<void (*function)(watcher &w, int)>
492     static void function_thunk (EV_P_ ev_watcher *w, int revents)
493     {
494       function (*static_cast<watcher *>(w), revents);
495     }
496
497     // simple callback
498     template<class K, void (K::*method)()>
499     void set (K *object) throw ()
500     {
501       set_ (object, method_noargs_thunk<K, method>);
502     }
503
504     template<class K, void (K::*method)()>
505     static void method_noargs_thunk (EV_P_ ev_watcher *w, int revents)
506     {
507       K *obj = static_cast<K *>(w->data);
508       (obj->*method) ();
509     }
510
511     void operator ()(int events = EV_UNDEF)
512     {
513       return ev_cb (static_cast<ev_watcher *>(this))
514         (static_cast<ev_watcher *>(this), events);
515     }
516
517     bool is_active () const throw ()
518     {
519       return ev_is_active (static_cast<const ev_watcher *>(this));
520     }
521
522     bool is_pending () const throw ()
523     {
524       return ev_is_pending (static_cast<const ev_watcher *>(this));
525     }
526
527     void feed_event (int revents) throw ()
528     {
529       ev_feed_event (EV_A_ static_cast<const ev_watcher *>(this), revents);
530     }
531   };
532
533   inline tstamp now () throw ()
534   {
535     return ev_time ();
536   }
537
538   inline void delay (tstamp interval) throw ()
539   {
540     ev_sleep (interval);
541   }
542
543   inline int version_major () throw ()
544   {
545     return ev_version_major ();
546   }
547
548   inline int version_minor () throw ()
549   {
550     return ev_version_minor ();
551   }
552
553   inline unsigned int supported_backends () throw ()
554   {
555     return ev_supported_backends ();
556   }
557
558   inline unsigned int recommended_backends () throw ()
559   {
560     return ev_recommended_backends ();
561   }
562
563   inline unsigned int embeddable_backends () throw ()
564   {
565     return ev_embeddable_backends ();
566   }
567
568   inline void set_allocator (void *(*cb)(void *ptr, long size)) throw ()
569   {
570     ev_set_allocator (cb);
571   }
572
573   inline void set_syserr_cb (void (*cb)(const char *msg)) throw ()
574   {
575     ev_set_syserr_cb (cb);
576   }
577
578   #if EV_MULTIPLICITY
579     #define EV_CONSTRUCT(cppstem,cstem)                                                 \
580       (EV_PX = get_default_loop ()) throw ()                                         \
581         : base<ev_ ## cstem, cppstem> (EV_A)                                            \
582       {                                                                                 \
583       }
584   #else
585     #define EV_CONSTRUCT(cppstem,cstem)                                                 \
586       () throw ()                                                                    \
587       {                                                                                 \
588       }
589   #endif
590
591   /* using a template here would require quite a bit more lines,
592    * so a macro solution was chosen */
593   #define EV_BEGIN_WATCHER(cppstem,cstem)                                               \
594                                                                                         \
595   struct cppstem : base<ev_ ## cstem, cppstem>                                          \
596   {                                                                                     \
597     void start () throw ()                                                           \
598     {                                                                                   \
599       ev_ ## cstem ## _start (EV_A_ static_cast<ev_ ## cstem *>(this));                 \
600     }                                                                                   \
601                                                                                         \
602     void stop () throw ()                                                            \
603     {                                                                                   \
604       ev_ ## cstem ## _stop (EV_A_ static_cast<ev_ ## cstem *>(this));                  \
605     }                                                                                   \
606                                                                                         \
607     cppstem EV_CONSTRUCT(cppstem,cstem)                                                 \
608                                                                                         \
609     ~cppstem () throw ()                                                             \
610     {                                                                                   \
611       stop ();                                                                          \
612     }                                                                                   \
613                                                                                         \
614     using base<ev_ ## cstem, cppstem>::set;                                             \
615                                                                                         \
616   private:                                                                              \
617                                                                                         \
618     cppstem (const cppstem &o);                                                         \
619                                                                                         \
620     cppstem & operator =(const cppstem &o);                                             \
621                                                                                         \
622   public:
623
624   #define EV_END_WATCHER(cppstem,cstem)                                                 \
625   };
626
627   EV_BEGIN_WATCHER (io, io)
628     void set (int fd, int events) throw ()
629     {
630       int active = is_active ();
631       if (active) stop ();
632       ev_io_set (static_cast<ev_io *>(this), fd, events);
633       if (active) start ();
634     }
635
636     void set (int events) throw ()
637     {
638       int active = is_active ();
639       if (active) stop ();
640       ev_io_set (static_cast<ev_io *>(this), fd, events);
641       if (active) start ();
642     }
643
644     void start (int fd, int events) throw ()
645     {
646       set (fd, events);
647       start ();
648     }
649   EV_END_WATCHER (io, io)
650
651   EV_BEGIN_WATCHER (timer, timer)
652     void set (ev_tstamp after, ev_tstamp repeat = 0.) throw ()
653     {
654       int active = is_active ();
655       if (active) stop ();
656       ev_timer_set (static_cast<ev_timer *>(this), after, repeat);
657       if (active) start ();
658     }
659
660     void start (ev_tstamp after, ev_tstamp repeat = 0.) throw ()
661     {
662       set (after, repeat);
663       start ();
664     }
665
666     void again () throw ()
667     {
668       ev_timer_again (EV_A_ static_cast<ev_timer *>(this));
669     }
670   EV_END_WATCHER (timer, timer)
671
672   #if EV_PERIODIC_ENABLE
673   EV_BEGIN_WATCHER (periodic, periodic)
674     void set (ev_tstamp at, ev_tstamp interval = 0.) throw ()
675     {
676       int active = is_active ();
677       if (active) stop ();
678       ev_periodic_set (static_cast<ev_periodic *>(this), at, interval, 0);
679       if (active) start ();
680     }
681
682     void start (ev_tstamp at, ev_tstamp interval = 0.) throw ()
683     {
684       set (at, interval);
685       start ();
686     }
687
688     void again () throw ()
689     {
690       ev_periodic_again (EV_A_ static_cast<ev_periodic *>(this));
691     }
692   EV_END_WATCHER (periodic, periodic)
693   #endif
694
695   EV_BEGIN_WATCHER (sig, signal)
696     void set (int signum) throw ()
697     {
698       int active = is_active ();
699       if (active) stop ();
700       ev_signal_set (static_cast<ev_signal *>(this), signum);
701       if (active) start ();
702     }
703
704     void start (int signum) throw ()
705     {
706       set (signum);
707       start ();
708     }
709   EV_END_WATCHER (sig, signal)
710
711   EV_BEGIN_WATCHER (child, child)
712     void set (int pid) throw ()
713     {
714       int active = is_active ();
715       if (active) stop ();
716       ev_child_set (static_cast<ev_child *>(this), pid);
717       if (active) start ();
718     }
719
720     void start (int pid) throw ()
721     {
722       set (pid);
723       start ();
724     }
725   EV_END_WATCHER (child, child)
726
727   #if EV_STAT_ENABLE
728   EV_BEGIN_WATCHER (stat, stat)
729     void set (const char *path, ev_tstamp interval = 0.) throw ()
730     {
731       int active = is_active ();
732       if (active) stop ();
733       ev_stat_set (static_cast<ev_stat *>(this), path, interval);
734       if (active) start ();
735     }
736
737     void start (const char *path, ev_tstamp interval = 0.) throw ()
738     {
739       stop ();
740       set (path, interval);
741       start ();
742     }
743
744     void update () throw ()
745     {
746       ev_stat_stat (EV_A_ static_cast<ev_stat *>(this));
747     }
748   EV_END_WATCHER (stat, stat)
749   #endif
750
751   EV_BEGIN_WATCHER (idle, idle)
752     void set () throw () { }
753   EV_END_WATCHER (idle, idle)
754
755   EV_BEGIN_WATCHER (prepare, prepare)
756     void set () throw () { }
757   EV_END_WATCHER (prepare, prepare)
758
759   EV_BEGIN_WATCHER (check, check)
760     void set () throw () { }
761   EV_END_WATCHER (check, check)
762
763   #if EV_EMBED_ENABLE
764   EV_BEGIN_WATCHER (embed, embed)
765     void start (struct ev_loop *embedded_loop) throw ()
766     {
767       stop ();
768       ev_embed_set (static_cast<ev_embed *>(this), embedded_loop);
769       start ();
770     }
771
772     void sweep ()
773     {
774       ev_embed_sweep (EV_A_ static_cast<ev_embed *>(this));
775     }
776   EV_END_WATCHER (embed, embed)
777   #endif
778
779   #if EV_FORK_ENABLE
780   EV_BEGIN_WATCHER (fork, fork)
781     void set () throw () { }
782   EV_END_WATCHER (fork, fork)
783   #endif
784
785   #undef EV_PX
786   #undef EV_PX_
787   #undef EV_CONSTRUCT
788   #undef EV_BEGIN_WATCHER
789   #undef EV_END_WATCHER
790
791 }
792
793 #undef EV_THROW
794
795 #endif
796