Leandro Lucarella, el 14 de enero a las 16:32 me escribiste:
> > 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);")
> 
> To implement this point, 2) is necessary if we don't want to be needed to
> explicitly set every watcher's loop, because the lack of a "standard" way
> to get the default loop.
> 
> > 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)
> 
> Here's patch that implement this scheme (over the original patch). Even if
> it's nice to stay close to the C API and to avoid the posibility of
> instantiating 2 default loops from the root, I think the usage is a little
> less intuitive in a C++ environment.

Third iteration =)

Main changes:
* 1) and 2) has been implemented.
* Now the loops methods to start and stop the loop match the C API (loop()
  and unloop()).
* Some bugfixes.
* loop_ref is renamed to loop_base and it's an abstract class (not a
  "pointer wrapper"). It's non-copiable since now loop_base is not
  instantiable.
* Watchers store a loop_base pointer instead of an ev_loop pointer.
* Some readonly attributes are now private/protected, providing accessor
  methods (e.g. w.loop()).
* is_default was removed from loop_base, since now the class matches the
  type of loop (is_default == dynamic_cast< loop_default* >(loop_ptr)).
* Add a lot of ev_once () flavors to loop_base.
* Add feed_event () to base watcher, and feed_fd_event () and
  feed_signal_event () loop_base.

A new patch (with all the changes) and a new example (now with a timer
watcher) are attached. Again, this is a rough patch, if you like it,
cleaning and documentation will follow =)

Thank you!

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
La esperanza es una amiga que nos presta la ilusión.
diff --git a/ev++.h b/ev++.h
index e447998..93644f2 100644
--- a/ev++.h
+++ b/ev++.h
@@ -45,18 +45,318 @@
 #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") {}
+  };
+
+#if EV_MULTIPLICITY
+#  define EV_AX  _loop
+#  define EV_AX_ _loop,
+#else
+#  define EV_AX
+#  define EV_AX_ ,
+#endif
+
+  struct loop_base
+  {
+
+#if EV_MULTIPLICITY
+    operator struct ev_loop * () const throw ()
+    {
+      return _loop;
+    }
+
+    operator const struct ev_loop * () const throw ()
+    {
+      return _loop;
+    }
+
+    virtual
+#endif
+    ~loop_base () throw ()
+    {
+    }
+
+    void loop (int flags = 0) throw ()
+    {
+      ev_loop (EV_AX_ flags);
+    }
+
+    void unloop (how_t how = ALL) throw ()
+    {
+      ev_unloop (EV_AX_ how);
+    }
+
+    virtual void fork () throw () = 0;
+
+    unsigned int count () const throw ()
+    {
+      return ev_loop_count (EV_AX);
+    }
+
+    unsigned int backend () const throw ()
+    {
+      return ev_backend (EV_AX);
+    }
+
+    tstamp now () const throw ()
+    {
+      return ev_now (EV_AX);
+    }
+
+    void ref () throw ()
+    {
+      ev_ref (EV_AX);
+    }
+
+    void unref () throw ()
+    {
+      ev_unref (EV_AX);
+    }
+
+    void set_io_collect_interval (tstamp interval) throw ()
+    {
+      ev_set_io_collect_interval (EV_AX_ interval);
+    }
+
+    void set_timeout_collect_interval (tstamp interval) throw ()
+    {
+      ev_set_timeout_collect_interval (EV_AX_ interval);
+    }
+
+    // function callback
+    void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void* arg = 0)
+    {
+      ev_once (EV_AX_ fd, events, timeout, cb, arg);
+    }
+
+    // method callback
+    template<class K, void (K::*method)(int)>
+    void once (int fd, int events, tstamp timeout, K *object)
+    {
+      once (fd, events, timeout, method_thunk<K, method>, object);
+    }
+
+    template<class K, void (K::*method)(int)>
+    static void method_thunk (int revents, void* arg)
+    {
+      K *obj = static_cast<K *>(arg);
+      (obj->*method) (revents);
+    }
+
+    // const method callback
+    template<class K, void (K::*method)(int) const>
+    void once (int fd, int events, tstamp timeout, const K *object)
+    {
+      once (fd, events, timeout, const_method_thunk<K, method>, object);
+    }
+
+    template<class K, void (K::*method)(int) const>
+    static void const_method_thunk (int revents, void* arg)
+    {
+      K *obj = static_cast<K *>(arg);
+      (obj->*method) (revents);
+    }
+
+    // simple method callback
+    template<class K, void (K::*method)()>
+    void once (int fd, int events, tstamp timeout, K *object)
+    {
+      once (fd, events, timeout, method_noargs_thunk<K, method>, object);
+    }
+
+    template<class K, void (K::*method)()>
+    static void method_noargs_thunk (int revents, void* arg)
+    {
+      K *obj = static_cast<K *>(arg);
+      (obj->*method) ();
+    }
+
+    // simpler function callback
+    template<void (*cb)(int)>
+    void once (int fd, int events, tstamp timeout)
+    {
+      once (fd, events, timeout, simpler_func_thunk<cb>);
+    }
+
+    template<void (*cb)(int)>
+    static void simpler_func_thunk (int revents, void* arg)
+    {
+      (*cb) (revents);
+    }
+
+    // simplest function callback
+    template<void (*cb)()>
+    void once (int fd, int events, tstamp timeout)
+    {
+      once (fd, events, timeout, simplest_func_thunk<cb>);
+    }
+
+    template<void (*cb)()>
+    static void simplest_func_thunk (int revents, void* arg)
+    {
+      (*cb) ();
+    }
+
+    void feed_fd_event (int fd, int revents)
+    {
+      ev_feed_fd_event (EV_AX_ fd, revents);
+    }
+
+    void feed_signal_event (int signum)
+    {
+      ev_feed_signal_event (EV_AX_ signum);
+    }
+
+  protected:
+
+#if EV_MULTIPLICITY
+    struct ev_loop* _loop;
+#endif
+
+    loop_base (EV_P) throw (bad_loop)
+#if EV_MULTIPLICITY
+      : _loop (EV_A)
+#endif
+    {
+      if (!EV_A)
+        throw bad_loop ();
+    }
+
+  private:
+
+    loop_base (const loop_base &);
+
+    loop_base & operator= (const loop_base &);
+
+  };
+
+#if EV_MULTIPLICITY
+  struct loop_simple: loop_base
+  {
+
+    loop_simple (unsigned int flags = AUTO) throw (bad_loop)
+      : loop_base (ev_loop_new (flags))
+    {
+    }
+
+    ~loop_simple () throw ()
+    {
+      ev_loop_destroy (_loop);
+    }
+
+    void fork () throw ()
+    {
+      ev_loop_fork (_loop);
+    }
+
+  private:
+
+    loop_simple (const loop_simple &);
+
+    loop_simple & operator= (const loop_simple &);
+
+  };
+#endif
+
+  struct loop_default;
+
+  loop_default&
+  default_loop (int flags = 0);
+
+  struct loop_default: loop_base
+  {
+
+    ~loop_default () throw ()
+    {
+      ev_default_destroy ();
+    }
+
+    void fork () throw ()
+    {
+      ev_default_fork ();
+    }
+
+  protected:
+
+    loop_default (unsigned int flags = AUTO) throw (bad_loop)
+      : loop_base (ev_default_loop (flags))
+    {
+    }
+
+  private:
+
+    loop_default (const loop_default &);
+
+    loop_default & operator= (const loop_default &);
+
+    friend loop_default& default_loop (int flags);
+
+  };
+
+  inline
+  loop_default&
+  default_loop (int flags)
+  {
+    static loop_default l (flags);
+    return l;
+  }
+
+  #undef EV_AX
+  #undef EV_AX_
+
   template<class ev_watcher, class watcher>
   struct base : ev_watcher
   {
     #if EV_MULTIPLICITY
-      EV_P;
+      loop_base *_loop;
+
+      void set (loop_base &loop) throw ()
+      {
+        _loop = &loop;
+      }
+
+      loop_base& loop () throw ()
+      {
+        return *_loop;
+      }
 
-      void set (EV_P)
+      const loop_base& loop () const throw ()
       {
-        this->EV_A = EV_A;
+        return *_loop;
       }
     #endif
 
@@ -141,6 +441,11 @@ namespace ev {
     {
       return ev_is_pending (static_cast<const ev_watcher *>(this));
     }
+
+    void feed_event (int revents)
+    {
+      ev_feed_event (loop (), static_cast<const ev_watcher *>(this), revents);
+    }
   };
 
   enum {
@@ -161,24 +466,66 @@ namespace ev {
     ERROR    = EV_ERROR,
   };
 
-  typedef ev_tstamp tstamp;
+  inline tstamp time ()
+  {
+    return ev_time ();
+  }
+
+  inline void sleep (tstamp interval)
+  {
+    ev_sleep (interval);
+  }
+
+  inline int version_major ()
+  {
+    return ev_version_major ();
+  }
+
+  inline int version_minor ()
+  {
+    return ev_version_minor ();
+  }
 
-  inline ev_tstamp now (EV_P)
+  inline unsigned int supported_backends ()
   {
-    return ev_now (EV_A);
+    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);
   }
 
   #if EV_MULTIPLICITY
     #define EV_CONSTRUCT                                                                \
-      (EV_P = EV_DEFAULT)                                                               \
+      (loop_base& loop = default_loop ())                                               \
       {                                                                                 \
-        set (EV_A);                                                                     \
+        set (loop);                                                                     \
       }
+    #define EV_AX  EV_A ()
+    #define EV_AX_ EV_A (),
   #else
     #define EV_CONSTRUCT                                                                \
       ()                                                                                \
       {                                                                                 \
       }
+    #define EV_AX
+    #define EV_AX_ ,
   #endif
 
   /* using a template here would require quite a bit more lines,
@@ -189,12 +536,12 @@ namespace ev {
   {                                                                                     \
     void start ()                                                                       \
     {                                                                                   \
-      ev_ ## cstem ## _start (EV_A_ static_cast<ev_ ## cstem *>(this));                 \
+      ev_ ## cstem ## _start (EV_AX_ static_cast<ev_ ## cstem *>(this));         \
     }                                                                                   \
                                                                                         \
     void stop ()                                                                        \
     {                                                                                   \
-      ev_ ## cstem ## _stop (EV_A_ static_cast<ev_ ## cstem *>(this));                  \
+      ev_ ## cstem ## _stop (EV_AX_ static_cast<ev_ ## cstem *>(this));          \
     }                                                                                   \
                                                                                         \
     cppstem EV_CONSTRUCT                                                                \
@@ -235,7 +582,7 @@ namespace ev {
       if (active) start ();
     }
 
-    void start (int fd, int events)
+    void start (int fd, int events = READ)
     {
       set (fd, events);
       start ();
@@ -259,7 +606,7 @@ namespace ev {
 
     void again ()
     {
-      ev_timer_again (EV_A_ static_cast<ev_timer *>(this));
+      ev_timer_again (EV_AX_ static_cast<ev_timer *>(this));
     }
   EV_END_WATCHER (timer, timer)
 
@@ -281,7 +628,7 @@ namespace ev {
 
     void again ()
     {
-      ev_periodic_again (EV_A_ static_cast<ev_periodic *>(this));
+      ev_periodic_again (EV_AX_ static_cast<ev_periodic *>(this));
     }
   EV_END_WATCHER (periodic, periodic)
   #endif
@@ -337,7 +684,7 @@ namespace ev {
 
     void update ()
     {
-      ev_stat_stat (EV_A_ static_cast<ev_stat *>(this));
+      ev_stat_stat (EV_AX_ static_cast<ev_stat *>(this));
     }
   EV_END_WATCHER (stat, stat)
   #endif
@@ -365,7 +712,7 @@ namespace ev {
 
     void sweep ()
     {
-      ev_embed_sweep (EV_A_ static_cast<ev_embed *>(this));
+      ev_embed_sweep (EV_AX_ static_cast<ev_embed *>(this));
     }
   EV_END_WATCHER (embed, embed)
   #endif
@@ -377,8 +724,11 @@ namespace ev {
   #endif
 
   #undef EV_CONSTRUCT
+  #undef EV_AX
+  #undef EV_AX_
   #undef EV_BEGIN_WATCHER
   #undef EV_END_WATCHER
+
 }
 
 #endif
#include <ev++.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>


/* called when data readable on stdin */
struct myclass
{
	void io_cb (ev::io &w, int revents)
	{
		printf ("stdin ready\n");
		char buff[BUFSIZ];
		buff[0] = '\0';
		int r = read (w.fd, buff, BUFSIZ);
		printf ("%d bytes read: %s", r, buff);
		w.stop (); /* just a syntax example */
		// same as w.loop ().unloop (ev::ONE); in this example
		ev::default_loop ().unloop (ev::ONE); /* leave one loop call */
	}
	void
	timeout_cb (ev::timer &w, int revents)
	{
		printf ("timeout!\n");
		// simulate activity on STDIN_FILENO
		ev::default_loop ().feed_fd_event (0, ev::READ);
	}
};

int
main (void)
{
	// If we don't initialize the default loop, it still works.
	// Is this expected behaviour?
	//ev::default_loop ();

	int flags;
	if ((flags = fcntl (0, F_GETFL, 0)) < 0)
		perror ("fcntl F_GETFL");
	if (fcntl (0, F_SETFL, flags | O_NONBLOCK) < 0)
		perror ("fcntl F_SETFL");

	myclass obj;

	// io event
	ev::io iow;
	iow.set <myclass, &myclass::io_cb> (&obj);

	/* start watching fd 0 for reading (default) */
	iow.start (/*STDIN_FILENO*/ 0);

	// timeout event
	ev::timer tw (ev::default_loop ()); // just to show how to pass a loop
	tw.set <myclass, &myclass::timeout_cb> (&obj);

	/* simple non-repeating 5.5 second timeout */
	tw.start (5.5);

	/* loop till timeout or data ready */
	ev::default_loop ().loop ();

	return 0;
}


_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to