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
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev