]> rtime.felk.cvut.cz Git - sojka/libev.git/commitdiff
*** empty log message ***
authorMarc Alexander Lehmann <libev@schmorp.de>
Tue, 11 Jan 2011 02:15:58 +0000 (02:15 +0000)
committerMarc Alexander Lehmann <libev@schmorp.de>
Tue, 11 Jan 2011 02:15:58 +0000 (02:15 +0000)
Changes
ev.c
ev.pod

diff --git a/Changes b/Changes
index 061cf11e1d6f4d5bb15a369edd549f98befe2347..6aa134769f3bf634c8a24f7e924c2bf2c2263bc2 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,8 +1,5 @@
 Revision history for libev, a high-performance and full-featured event loop.
 
-TODO: move some other examples to common idioms? combining watchers,
-thread usage, coroutine switch?
-
 4.03
        - officially support polling files with all backends.
        - support files, /dev/zero etc. the same way as select in the epoll
diff --git a/ev.c b/ev.c
index c7e5077712003cfaef3ea55734718536b401f9b6..1a8b3192f536257414bda1a0ecec4af87a3bec53 100644 (file)
--- a/ev.c
+++ b/ev.c
@@ -2113,9 +2113,6 @@ ev_invoke_pending (EV_P)
       {
         ANPENDING *p = pendings [pri] + --pendingcnt [pri];
 
-        /*assert (("libev: non-pending watcher on pending list", p->w->pending));*/
-        /* ^ this is no longer true, as pending_w could be here */
-
         p->w->pending = 0;
         EV_CB_INVOKE (p->w, p->events);
         EV_FREQUENT_CHECK;
diff --git a/ev.pod b/ev.pod
index 3d4852e28ac631318d93808a870f827bd93f97f9..244bb1420710f5c0497155077bf49f2f99a2630b 100644 (file)
--- a/ev.pod
+++ b/ev.pod
@@ -1359,70 +1359,8 @@ functions that do not need a watcher.
 
 =back
 
-=head2 ASSOCIATING CUSTOM DATA WITH A WATCHER
-
-Each watcher has, by default, a member C<void *data> that you can change
-and read at any time: libev will completely ignore it. This can be used
-to associate arbitrary data with your watcher. If you need more data and
-don't want to allocate memory and store a pointer to it in that data
-member, you can also "subclass" the watcher type and provide your own
-data:
-
-   struct my_io
-   {
-     ev_io io;
-     int otherfd;
-     void *somedata;
-     struct whatever *mostinteresting;
-   };
-
-   ...
-   struct my_io w;
-   ev_io_init (&w.io, my_cb, fd, EV_READ);
-
-And since your callback will be called with a pointer to the watcher, you
-can cast it back to your own type:
-
-   static void my_cb (struct ev_loop *loop, ev_io *w_, int revents)
-   {
-     struct my_io *w = (struct my_io *)w_;
-     ...
-   }
-
-More interesting and less C-conformant ways of casting your callback type
-instead have been omitted.
-
-Another common scenario is to use some data structure with multiple
-embedded watchers:
-
-   struct my_biggy
-   {
-     int some_data;
-     ev_timer t1;
-     ev_timer t2;
-   }
-
-In this case getting the pointer to C<my_biggy> is a bit more
-complicated: Either you store the address of your C<my_biggy> struct
-in the C<data> member of the watcher (for woozies), or you need to use
-some pointer arithmetic using C<offsetof> inside your watchers (for real
-programmers):
-
-   #include <stddef.h>
-
-   static void
-   t1_cb (EV_P_ ev_timer *w, int revents)
-   {
-     struct my_biggy big = (struct my_biggy *)
-       (((char *)w) - offsetof (struct my_biggy, t1));
-   }
-
-   static void
-   t2_cb (EV_P_ ev_timer *w, int revents)
-   {
-     struct my_biggy big = (struct my_biggy *)
-       (((char *)w) - offsetof (struct my_biggy, t2));
-   }
+See also the L<ASSOCIATING CUSTOM DATA WITH A WATCHER> and L<BUILDING YOUR
+OWN COMPOSITE WATCHERS> idioms.
 
 =head2 WATCHER STATES
 
@@ -3458,6 +3396,74 @@ This section explains some common idioms that are not immediately
 obvious. Note that examples are sprinkled over the whole manual, and this
 section only contains stuff that wouldn't fit anywhere else.
 
+=head2 ASSOCIATING CUSTOM DATA WITH A WATCHER
+
+Each watcher has, by default, a C<void *data> member that you can read
+or modify at any time: libev will completely ignore it. This can be used
+to associate arbitrary data with your watcher. If you need more data and
+don't want to allocate memory separately and store a pointer to it in that
+data member, you can also "subclass" the watcher type and provide your own
+data:
+
+   struct my_io
+   {
+     ev_io io;
+     int otherfd;
+     void *somedata;
+     struct whatever *mostinteresting;
+   };
+
+   ...
+   struct my_io w;
+   ev_io_init (&w.io, my_cb, fd, EV_READ);
+
+And since your callback will be called with a pointer to the watcher, you
+can cast it back to your own type:
+
+   static void my_cb (struct ev_loop *loop, ev_io *w_, int revents)
+   {
+     struct my_io *w = (struct my_io *)w_;
+     ...
+   }
+
+More interesting and less C-conformant ways of casting your callback
+function type instead have been omitted.
+
+=head2 BUILDING YOUR OWN COMPOSITE WATCHERS
+
+Another common scenario is to use some data structure with multiple
+embedded watchers, in effect creating your own watcher that combines
+multiple libev event sources into one "super-watcher":
+
+   struct my_biggy
+   {
+     int some_data;
+     ev_timer t1;
+     ev_timer t2;
+   }
+
+In this case getting the pointer to C<my_biggy> is a bit more
+complicated: Either you store the address of your C<my_biggy> struct in
+the C<data> member of the watcher (for woozies or C++ coders), or you need
+to use some pointer arithmetic using C<offsetof> inside your watchers (for
+real programmers):
+
+   #include <stddef.h>
+
+   static void
+   t1_cb (EV_P_ ev_timer *w, int revents)
+   {
+     struct my_biggy big = (struct my_biggy *)
+       (((char *)w) - offsetof (struct my_biggy, t1));
+   }
+
+   static void
+   t2_cb (EV_P_ ev_timer *w, int revents)
+   {
+     struct my_biggy big = (struct my_biggy *)
+       (((char *)w) - offsetof (struct my_biggy, t2));
+   }
+
 =head2 MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS
 
 Often (especially in GUI toolkits) there are places where you have
@@ -3635,7 +3641,63 @@ an event loop currently blocking in the kernel will have no knowledge
 about the newly added timer. By waking up the loop it will pick up any new
 watchers in the next event loop iteration.
 
-=back
+=head2 THREADS, COROUTINES, CONTINUATIONS, QUEUES... INSTEAD OF CALLBACKS
+
+While the overhead of a callback that e.g. schedules a thread is small, it
+is still an overhead. If you embed libev, and your main usage is with some
+kind of threads or coroutines, you might want to customise libev so that
+doesn't need callbacks anymore.
+
+Imagine you have coroutines that you can switch to using a function
+C<switch_to (coro)>, that libev runs in a coroutine called C<libev_coro>
+and that due to some magic, the currently active coroutine is stored in a
+global called C<current_coro>. Then you can build your own "wait for libev
+event" primitive by changing C<EV_CB_DECLARE> and C<EV_CB_INVOKE> (note
+the differing C<;> conventions):
+
+   #define EV_CB_DECLARE(type)   struct my_coro *cb;
+   #define EV_CB_INVOKE(watcher) switch_to ((watcher)->cb)
+
+That means instead of having a C callback function, you store the
+coroutine to switch to in each watcher, and instead of having libev call
+your callback, you instead have it switch to that coroutine.
+
+A coroutine might now wait for an event with a function called
+C<wait_for_event>. (the watcher needs to be started, as always, but it doesn't
+matter when, or whether the watcher is active or not when this function is
+called):
+
+   void
+   wait_for_event (ev_watcher *w)
+   {
+     ev_cb_set (w) = current_coro;
+     switch_to (libev_coro);
+   }
+
+That basically suspends the coroutine inside C<wait_for_event> and
+continues the libev coroutine, which, when appropriate, switches back to
+this or any other coroutine. I am sure if you sue this your own :)
+
+You can do similar tricks if you have, say, threads with an event queue -
+instead of storing a coroutine, you store the queue object and instead of
+switching to a coroutine, you push the watcher onto the queue and notify
+any waiters.
+
+To embed libev, see L<EMBEDDING>, but in short, it's easiest to create two
+files, F<my_ev.h> and F<my_ev.c> that include the respective libev files:
+
+   // my_ev.h
+   #define EV_CB_DECLARE(type)   struct my_coro *cb;
+   #define EV_CB_INVOKE(watcher) switch_to ((watcher)->cb);
+   #include "../libev/ev.h"
+
+   // my_ev.c
+   #define EV_H "my_ev.h"
+   #include "../libev/ev.c"
+
+And then use F<my_ev.h> when you would normally use F<ev.h>, and compile
+F<my_ev.c> into your project. When properly specifying include paths, you
+can even use F<ev.h> as header file name directly.
 
 
 =head1 LIBEVENT EMULATION
@@ -4575,7 +4637,7 @@ And a F<ev_cpp.C> implementation file that contains libev proper and is compiled
    #include "ev_cpp.h"
    #include "ev.c"
 
-=head1 INTERACTION WITH OTHER PROGRAMS OR LIBRARIES
+=head1 INTERACTION WITH OTHER PROGRAMS, LIBRARIES OR THE ENVIRONMENT
 
 =head2 THREADS AND COROUTINES