X-Git-Url: https://git.llucax.com/software/libev.git/blobdiff_plain/480621758fe1687120978562a553920ed46e1b7e..b4ea51ffb8ad1cf82bc52c03035eb335e2b4c88c:/ev.pod diff --git a/ev.pod b/ev.pod index ef9892e..237bdb0 100644 --- a/ev.pod +++ b/ev.pod @@ -488,8 +488,9 @@ usually a better approach for this kind of thing. Here are the gory details of what C does: + - Before the first iteration, call any pending watchers. * If there are no active watchers (reference count is zero), return. - - Queue prepare watchers and then call all outstanding watchers. + - Queue all prepare watchers and then call all outstanding watchers. - If we have been forked, recreate the kernel state. - Update the kernel state with all outstanding changes. - Update the "event loop time". @@ -1483,6 +1484,16 @@ of lower priority, but only once, using idle watchers to keep the event loop from blocking if lower-priority coroutines are active, thus mapping low-priority coroutines to idle/background tasks). +It is recommended to give C watchers highest (C) +priority, to ensure that they are being run before any other watchers +after the poll. Also, C watchers (and C watchers, +too) should not activate ("feed") events into libev. While libev fully +supports this, they will be called before other C watchers did +their job. As C watchers are often used to embed other event +loops those other event loops might be in an unusable state until their +C watcher ran (always remind yourself to coexist peacefully with +others). + =over 4 =item ev_prepare_init (ev_prepare *, callback) @@ -1495,10 +1506,18 @@ macros, but using them is utterly, utterly and completely pointless. =back -Example: To include a library such as adns, you would add IO watchers -and a timeout watcher in a prepare handler, as required by libadns, and -in a check watcher, destroy them and call into libadns. What follows is -pseudo-code only of course: +There are a number of principal ways to embed other event loops or modules +into libev. Here are some ideas on how to include libadns into libev +(there is a Perl module named C that does this, which you could +use for an actually working example. Another Perl module named C +embeds a Glib main context into libev, and finally, C embeds EV +into the Glib event loop). + +Method 1: Add IO watchers and a timeout watcher in a prepare handler, +and in a check watcher, destroy them and call into libadns. What follows +is pseudo-code only of course. This requires you to either use a low +priority for the check watcher or use C explicitly, as +the callbacks for the IO/timeout watchers might not have been called yet. static ev_io iow [nfd]; static ev_timer tw; @@ -1506,11 +1525,6 @@ pseudo-code only of course: static void io_cb (ev_loop *loop, ev_io *w, int revents) { - // set the relevant poll flags - // could also call adns_processreadable etc. here - struct pollfd *fd = (struct pollfd *)w->data; - if (revents & EV_READ ) fd->revents |= fd->events & POLLIN; - if (revents & EV_WRITE) fd->revents |= fd->events & POLLOUT; } // create io watchers for each fd and a timer before blocking @@ -1526,7 +1540,7 @@ pseudo-code only of course: ev_timer_init (&tw, 0, timeout * 1e-3); ev_timer_start (loop, &tw); - // create on ev_io per pollfd + // create one ev_io per pollfd for (int i = 0; i < nfd; ++i) { ev_io_init (iow + i, io_cb, fds [i].fd, @@ -1534,7 +1548,6 @@ pseudo-code only of course: | (fds [i].events & POLLOUT ? EV_WRITE : 0))); fds [i].revents = 0; - iow [i].data = fds + i; ev_io_start (loop, iow + i); } } @@ -1546,11 +1559,80 @@ pseudo-code only of course: ev_timer_stop (loop, &tw); for (int i = 0; i < nfd; ++i) - ev_io_stop (loop, iow + i); + { + // set the relevant poll flags + // could also call adns_processreadable etc. here + struct pollfd *fd = fds + i; + int revents = ev_clear_pending (iow + i); + if (revents & EV_READ ) fd->revents |= fd->events & POLLIN; + if (revents & EV_WRITE) fd->revents |= fd->events & POLLOUT; + + // now stop the watcher + ev_io_stop (loop, iow + i); + } adns_afterpoll (adns, fds, nfd, timeval_from (ev_now (loop)); } +Method 2: This would be just like method 1, but you run C +in the prepare watcher and would dispose of the check watcher. + +Method 3: If the module to be embedded supports explicit event +notification (adns does), you can also make use of the actual watcher +callbacks, and only destroy/create the watchers in the prepare watcher. + + static void + timer_cb (EV_P_ ev_timer *w, int revents) + { + adns_state ads = (adns_state)w->data; + update_now (EV_A); + + adns_processtimeouts (ads, &tv_now); + } + + static void + io_cb (EV_P_ ev_io *w, int revents) + { + adns_state ads = (adns_state)w->data; + update_now (EV_A); + + if (revents & EV_READ ) adns_processreadable (ads, w->fd, &tv_now); + if (revents & EV_WRITE) adns_processwriteable (ads, w->fd, &tv_now); + } + + // do not ever call adns_afterpoll + +Method 4: Do not use a prepare or check watcher because the module you +want to embed is too inflexible to support it. Instead, youc na override +their poll function. The drawback with this solution is that the main +loop is now no longer controllable by EV. The C module does +this. + + static gint + event_poll_func (GPollFD *fds, guint nfds, gint timeout) + { + int got_events = 0; + + for (n = 0; n < nfds; ++n) + // create/start io watcher that sets the relevant bits in fds[n] and increment got_events + + if (timeout >= 0) + // create/start timer + + // poll + ev_loop (EV_A_ 0); + + // stop timer again + if (timeout >= 0) + ev_timer_stop (EV_A_ &to); + + // stop io watchers again - their callbacks should have set + for (n = 0; n < nfds; ++n) + ev_io_stop (EV_A_ iow [n]); + + return got_events; + } + =head2 C - when one backend isn't enough... @@ -1846,14 +1928,21 @@ Example: simple class declaration and watcher initialisation ev::io iow; iow.set (&obj); -=item w->set (void (*function)(watcher &w, int), void *data = 0) +=item w->set (void *data = 0) Also sets a callback, but uses a static method or plain function as callback. The optional C argument will be stored in the watcher's C member and is free for you to use. +The prototype of the C must be C. + See the method-C above for more details. +Example: + + static void io_cb (ev::io &w, int revents) { } + iow.set (); + =item w->set (struct ev_loop *) Associates a different C with this watcher. You can only