Hi, following the "C++ APIs" thread [1], I came to the conclusion that I didn't like the "whole new wrapper" approach, because it didn't provide anything ev++.h have (or it would be too hard to implement, and I didn't thought it worth the effort, because there were too little benefit).
I tried the full wrapper approach, with the goal of making a "C++ binding", trying to hide all the C API (including ev.h only in the cpp files) but it didn't worked, and add another lib to link to, and lost the embedding capabilities. So I decided to improve ev++.h, at least as I see it =) Attached it a *rough* patch, that can be used as in the example file test.cpp. There are a few issues I'm not happy about, so I want to know your opinion before deciding what to do with them, and of course, I want to know if there is any interest in merging this to the official libev distribution =) What I'm not crazy about is: 1) Storing a ev_loop* in the watchers, instead of a loop_ref. But I'm affraid that not doing so could break some existing code. This leads to the ugly "ev::loop_ref (w.loop).stop (ev::ALL);" in the example (if a loop_ref could be stored, it looked like "w.loop.stop (ev::ALL);") 2) The default loop handling. Now a default loop has to be instantiated, and a simple check is done to ensure just one default loop exists, but with an ugly hack (via de default_loop_created() function) to avoid the need of object code (a class static variable would need it). This model is a little different to the C API, because you can't get the default loop from anywhere (at least not in the same way, but you can do it with something like loop_ref(ev_default_loop(0)), but it's not very nice). The easiest way to do that is making the default_loop a global variable, but it's a "userspace" hack. I thought of making a more singleton-approach (using a function to get/create the loop object if it doesn't exist, for example "get_default_loop(int flags = 0) { static default_loop* l = 0; if (!l) l = new default_loop(flags); return l; }" but this way you have to explicitly free the default loop). Now that I see this, maybe it could be "elegantly" solved using a reference: default_loop& get_default_loop(int flags = 0) { static default_loop l(flags); return l; } (class names could be rearranged to name this funtion default_loop() and the class loop_default, for example, to be more C API-consistent) The patch is embedding and EV_MULTIPLICITY aware, but it's not well tested (to be honest, I just tested it with the example attached, with a default libev build -EV_MULTIPLICITY = 1-). [1] http://permalink.gmane.org/gmane.comp.lib.ev/9 -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Qué sabía Galileo de astronomía, Mendieta! Lo que pasa es que en este país habla cualquiera. -- Inodoro Pereyra
Author: Leandro Lucarella <[EMAIL PROTECTED]> Date: Mon Jan 14 13:21:28 2008 -0200 Add loop hierarchy and some missing free functions. diff --git a/ev++.h b/ev++.h index 97e015c..edf7bcd 100644 --- a/ev++.h +++ b/ev++.h @@ -45,9 +45,202 @@ #else # include <ev.h> #endif +#include <stdexcept> namespace ev { + typedef ev_tstamp tstamp; + + enum + { + AUTO = EVFLAG_AUTO, + NOENV = EVFLAG_NOENV, + FORKCHECK = EVFLAG_FORKCHECK, + SELECT = EVBACKEND_SELECT, + POLL = EVBACKEND_POLL, + EPOLL = EVBACKEND_EPOLL, + KQUEUE = EVBACKEND_KQUEUE, + DEVPOLL = EVBACKEND_DEVPOLL, + PORT = EVBACKEND_PORT + }; + + enum + { + NONBLOCK = EVLOOP_NONBLOCK, + ONESHOT = EVLOOP_ONESHOT + }; + + enum how_t + { + ONE = EVUNLOOP_ONE, + ALL = EVUNLOOP_ALL + }; + + struct bad_loop: std::runtime_error + { + bad_loop() + : std::runtime_error("loop can't be initialized") {} + }; + + struct already_created: std::logic_error + { + bad_loop() + : std::runtime_error("there's already a default loop instantiated") {} + }; + + extern "C" + { + extern struct ev_loop *ev_default_loop_ptr; + } + + struct loop_ref + { + + loop_ref (EV_P) throw (bad_loop) +#if EV_MULTIPLICITY + : EV_A (EV_A), is_default (EV_A == ev_default_loop_ptr) +#endif + { + if (!EV_A) + throw bad_loop (); + } + +#if EV_MULTIPLICITY + virtual +#endif + ~loop_ref () throw () + { + } + +#if EV_MULTIPLICITY + operator struct ev_loop * () throw () + { + return EV_A; + } + + operator const struct ev_loop * () throw () + { + return EV_A; + } +#endif + + void start (int flags = 0) throw () + { + ev_loop (EV_A_ flags); + } + + void stop (how_t how = ALL) throw () + { + ev_unloop (EV_A_ how); + } + + void fork () throw () + { +#if EV_MULTIPLICITY + if (!is_default) + ev_loop_fork (EV_A); + else +#endif + ev_default_fork (); + } + + unsigned int count () const throw () + { + return ev_loop_count (EV_A); + } + + unsigned int backend () const throw () + { + return ev_backend (EV_A); + } + + tstamp now () const throw () + { + return ev_now (EV_A); + } + + void ref () throw () + { + ev_ref (EV_A); + } + + void unref () throw () + { + ev_unref (EV_A); + } + + void set_io_collect_interval (tstamp interval) throw () + { + ev_set_io_collect_interval (EV_A_ interval); + } + + void set_timeout_collect_interval (tstamp interval) throw () + { + ev_set_timeout_collect_interval (EV_A_ interval); + } + +#if EV_MULTIPLICITY + EV_P; + bool is_default; +#endif + }; + +#if EV_MULTIPLICITY + struct simple_loop: loop_ref + { + + simple_loop (unsigned int flags = AUTO) throw () + : loop_ref (ev_loop_new (flags)) + { + } + + ~simple_loop () throw () + { + ev_loop_destroy (EV_A); + } + + private: + + simple_loop (const simple_loop &); + + simple_loop & operator= (const simple_loop &); + + }; +#endif + + bool default_loop_created (int created = -1) + { + static bool is_created = false; + if (created != -1) + is_created = created; + return is_created; + } + + struct default_loop: loop_ref + { + + default_loop (unsigned int flags = AUTO) throw (already_created) + : loop_ref (ev_default_loop (flags)) + { + if (default_loop_created ()) + throw already_created (); + default_loop_created (true); + } + + ~default_loop () throw () + { + default_loop_created (false); + ev_default_destroy (); + } + + private: + + default_loop (const default_loop &); + + default_loop & operator= (const default_loop &); + + }; + template<class ev_watcher, class watcher> struct base : ev_watcher { @@ -161,14 +354,50 @@ namespace ev { ERROR = EV_ERROR, }; - typedef ev_tstamp tstamp; + inline tstamp time () + { + return ev_time (); + } - #if EV_MULTIPLICITY - inline ev_tstamp now (EV_P) + inline void sleep (tstamp interval) { - return ev_now (EV_A); + ev_sleep (interval); + } + + inline int version_major () + { + return ev_version_major (); + } + + inline int version_minor () + { + return ev_version_minor (); + } + + inline unsigned int supported_backends () + { + return ev_supported_backends (); + } + + inline unsigned int recommended_backends () + { + return ev_recommended_backends (); + } + + inline unsigned int embeddable_backends () + { + return ev_embeddable_backends (); + } + + inline void set_allocator (void *(*cb)(void *ptr, long size)) + { + ev_set_allocator (cb); + } + + inline void set_syserr_cb (void (*cb)(const char *msg)) + { + ev_set_syserr_cb (cb); } - #endif #if EV_MULTIPLICITY #define EV_CONSTRUCT \ @@ -237,7 +466,7 @@ namespace ev { if (active) start (); } - void start (int fd, int events) + void start (int fd, int events = READ) { set (fd, events); start (); @@ -381,6 +610,7 @@ namespace ev { #undef EV_CONSTRUCT #undef EV_BEGIN_WATCHER #undef EV_END_WATCHER + } #endif
#include <ev++.h> #include <stdio.h> #include <unistd.h> /* called when data readable on stdin */ struct myclass { void io_cb (ev::io &w, int revents) { char buff[BUFSIZ]; int r = read (w.fd, buff, BUFSIZ); printf ("stdin ready, %d bytes read: %s", r, buff); w.stop (); /* just a syntax example */ ev::loop_ref(w.loop).stop (ev::ALL); /* leave all loop calls */ } }; int main (void) { ev::default_loop loop; myclass obj; ev::io iow; iow.set <myclass, &myclass::io_cb> (&obj); /* start watching fd 0 for reading (default) */ iow.start (/*STDIN_FILENO*/ 0); /* loop till timeout or data ready */ loop.start (); return 0; }
_______________________________________________ libev mailing list libev@lists.schmorp.de http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev