From 2e4f855ad17fd958d1643d2170054734053033fc Mon Sep 17 00:00:00 2001 From: root Date: Tue, 27 Nov 2007 10:59:10 +0000 Subject: docs --- ev++.h | 5 ++- ev.3 | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ev.c | 37 +++++++++++++++++++++ ev.h | 45 +++++++++++++++++++------- ev.html | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- ev.pod | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- ev_vars.h | 6 ++++ ev_wrap.h | 3 ++ 8 files changed, 378 insertions(+), 18 deletions(-) diff --git a/ev++.h b/ev++.h index 9d0df26..ce18ca0 100644 --- a/ev++.h +++ b/ev++.h @@ -52,10 +52,13 @@ namespace ev { TIMEOUT = EV_TIMEOUT, PERIODIC = EV_PERIODIC, SIGNAL = EV_SIGNAL, + CHILD = EV_CHILD, + STAT = EV_STAT, IDLE = EV_IDLE, CHECK = EV_CHECK, PREPARE = EV_PREPARE, - CHILD = EV_CHILD, + FORK = EV_FORK, + EMBED = EV_EMBED, ERROR = EV_ERROR, }; diff --git a/ev.3 b/ev.3 index 31d1f6b..01e5c65 100644 --- a/ev.3 +++ b/ev.3 @@ -709,6 +709,15 @@ received events. Callbacks of both watcher types can start and stop as many watchers as they want, and all of them will be taken into account (for example, a \f(CW\*(C`ev_prepare\*(C'\fR watcher might start an idle watcher to keep \&\f(CW\*(C`ev_loop\*(C'\fR from blocking). +.ie n .IP """EV_EMBED""" 4 +.el .IP "\f(CWEV_EMBED\fR" 4 +.IX Item "EV_EMBED" +The embedded event loop specified in the \f(CW\*(C`ev_embed\*(C'\fR watcher needs attention. +.ie n .IP """EV_FORK""" 4 +.el .IP "\f(CWEV_FORK\fR" 4 +.IX Item "EV_FORK" +The event loop has been resumed in the child process after fork (see +\&\f(CW\*(C`ev_fork\*(C'\fR). .ie n .IP """EV_ERROR""" 4 .el .IP "\f(CWEV_ERROR\fR" 4 .IX Item "EV_ERROR" @@ -1615,6 +1624,21 @@ apropriate way for embedded loops. .IP "struct ev_loop *loop [read\-only]" 4 .IX Item "struct ev_loop *loop [read-only]" The embedded event loop. +.ie n .Sh """ev_fork"" \- the audacity to resume the event loop after a fork" +.el .Sh "\f(CWev_fork\fP \- the audacity to resume the event loop after a fork" +.IX Subsection "ev_fork - the audacity to resume the event loop after a fork" +Fork watchers are called when a \f(CW\*(C`fork ()\*(C'\fR was detected (usually because +whoever is a good citizen cared to tell libev about it by calling +\&\f(CW\*(C`ev_default_fork\*(C'\fR or \f(CW\*(C`ev_loop_fork\*(C'\fR). The invocation is done before the +event loop blocks next and before \f(CW\*(C`ev_check\*(C'\fR watchers are being called, +and only in the child after the fork. If whoever good citizen calling +\&\f(CW\*(C`ev_default_fork\*(C'\fR cheats and calls it in the wrong process, the fork +handlers will be invoked, too, of course. +.IP "ev_fork_init (ev_signal *, callback)" 4 +.IX Item "ev_fork_init (ev_signal *, callback)" +Initialises and configures the fork watcher \- it has no parameters of any +kind. There is a \f(CW\*(C`ev_fork_set\*(C'\fR macro, but using it is utterly pointless, +believe me. .SH "OTHER FUNCTIONS" .IX Header "OTHER FUNCTIONS" There are some other functions of possible interest. Described. Here. Now. @@ -1794,6 +1818,71 @@ the constructor. \& io.start (fd, ev::READ); \& } .Ve +.SH "MACRO MAGIC" +.IX Header "MACRO MAGIC" +Libev can be compiled with a variety of options, the most fundemantal is +\&\f(CW\*(C`EV_MULTIPLICITY\*(C'\fR. This option determines wether (most) functions and +callbacks have an initial \f(CW\*(C`struct ev_loop *\*(C'\fR argument. +.PP +To make it easier to write programs that cope with either variant, the +following macros are defined: +.ie n .IP """EV_A""\fR, \f(CW""EV_A_""" 4 +.el .IP "\f(CWEV_A\fR, \f(CWEV_A_\fR" 4 +.IX Item "EV_A, EV_A_" +This provides the loop \fIargument\fR for functions, if one is required (\*(L"ev +loop argument\*(R"). The \f(CW\*(C`EV_A\*(C'\fR form is used when this is the sole argument, +\&\f(CW\*(C`EV_A_\*(C'\fR is used when other arguments are following. Example: +.Sp +.Vb 3 +\& ev_unref (EV_A); +\& ev_timer_add (EV_A_ watcher); +\& ev_loop (EV_A_ 0); +.Ve +.Sp +It assumes the variable \f(CW\*(C`loop\*(C'\fR of type \f(CW\*(C`struct ev_loop *\*(C'\fR is in scope, +which is often provided by the following macro. +.ie n .IP """EV_P""\fR, \f(CW""EV_P_""" 4 +.el .IP "\f(CWEV_P\fR, \f(CWEV_P_\fR" 4 +.IX Item "EV_P, EV_P_" +This provides the loop \fIparameter\fR for functions, if one is required (\*(L"ev +loop parameter\*(R"). The \f(CW\*(C`EV_P\*(C'\fR form is used when this is the sole parameter, +\&\f(CW\*(C`EV_P_\*(C'\fR is used when other parameters are following. Example: +.Sp +.Vb 2 +\& // this is how ev_unref is being declared +\& static void ev_unref (EV_P); +.Ve +.Sp +.Vb 2 +\& // this is how you can declare your typical callback +\& static void cb (EV_P_ ev_timer *w, int revents) +.Ve +.Sp +It declares a parameter \f(CW\*(C`loop\*(C'\fR of type \f(CW\*(C`struct ev_loop *\*(C'\fR, quite +suitable for use with \f(CW\*(C`EV_A\*(C'\fR. +.ie n .IP """EV_DEFAULT""\fR, \f(CW""EV_DEFAULT_""" 4 +.el .IP "\f(CWEV_DEFAULT\fR, \f(CWEV_DEFAULT_\fR" 4 +.IX Item "EV_DEFAULT, EV_DEFAULT_" +Similar to the other two macros, this gives you the value of the default +loop, if multiple loops are supported (\*(L"ev loop default\*(R"). +.PP +Example: Declare and initialise a check watcher, working regardless of +wether multiple loops are supported or not. +.PP +.Vb 5 +\& static void +\& check_cb (EV_P_ ev_timer *w, int revents) +\& { +\& ev_check_stop (EV_A_ w); +\& } +.Ve +.PP +.Vb 4 +\& ev_check check; +\& ev_check_init (&check, check_cb); +\& ev_check_start (EV_DEFAULT_ &check); +\& ev_loop (EV_DEFAULT_ 0); +.Ve .SH "EMBEDDING" .IX Header "EMBEDDING" Libev can (and often is) directly embedded into host @@ -2022,6 +2111,10 @@ defined to be \f(CW0\fR, then they are not. .IX Item "EV_STAT_ENABLE" If undefined or defined to be \f(CW1\fR, then stat watchers are supported. If defined to be \f(CW0\fR, then they are not. +.IP "\s-1EV_FORK_ENABLE\s0" 4 +.IX Item "EV_FORK_ENABLE" +If undefined or defined to be \f(CW1\fR, then fork watchers are supported. If +defined to be \f(CW0\fR, then they are not. .IP "\s-1EV_MINIMAL\s0" 4 .IX Item "EV_MINIMAL" If you need to shave off some kilobytes of code at the expense of some diff --git a/ev.c b/ev.c index 40e2292..bf20d1a 100644 --- a/ev.c +++ b/ev.c @@ -1278,6 +1278,14 @@ ev_loop (EV_P_ int flags) while (activecnt) { + /* we might have forked, so reify kernel state if necessary */ + if (expect_false (postfork)) + if (forkcnt) + { + queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK); + call_pending (EV_A); + } + /* queue check watchers (and execute them) */ if (expect_false (preparecnt)) { @@ -1829,6 +1837,35 @@ ev_embed_stop (EV_P_ ev_embed *w) } #endif +#if EV_FORK_ENABLE +void +ev_fork_start (EV_P_ ev_fork *w) +{ + if (expect_false (ev_is_active (w))) + return; + + ev_start (EV_A_ (W)w, ++forkcnt); + array_needsize (ev_fork *, forks, forkmax, forkcnt, EMPTY2); + forks [forkcnt - 1] = w; +} + +void +ev_fork_stop (EV_P_ ev_fork *w) +{ + ev_clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + { + int active = ((W)w)->active; + forks [active - 1] = forks [--forkcnt]; + ((W)forks [active - 1])->active = active; + } + + ev_stop (EV_A_ (W)w); +} +#endif + /*****************************************************************************/ struct ev_once diff --git a/ev.h b/ev.h index 76f7a10..26ffe78 100644 --- a/ev.h +++ b/ev.h @@ -56,6 +56,10 @@ typedef double ev_tstamp; # define EV_STAT_ENABLE 1 #endif +#ifndef EV_FORK_ENABLE +# define EV_FORK_ENABLE 1 +#endif + #ifndef EV_EMBED_ENABLE # define EV_EMBED_ENABLE 1 #endif @@ -73,15 +77,15 @@ struct ev_loop; # define EV_P_ EV_P, # define EV_A loop # define EV_A_ EV_A, -# define EV_DEFAULT_A ev_default_loop (0) -# define EV_DEFAULT_A_ EV_DEFAULT_A, +# define EV_DEFAULT ev_default_loop (0) +# define EV_DEFAULT_ EV_DEFAULT, #else # define EV_P void # define EV_P_ # define EV_A # define EV_A_ -# define EV_DEFAULT_A -# define EV_DEFAULT_A_ +# define EV_DEFAULT +# define EV_DEFAULT_ # undef EV_EMBED_ENABLE #endif @@ -94,12 +98,13 @@ struct ev_loop; #define EV_TIMEOUT 0x00000100L /* timer timed out */ #define EV_PERIODIC 0x00000200L /* periodic timer timed out */ #define EV_SIGNAL 0x00000400L /* signal was received */ -#define EV_IDLE 0x00000800L /* event loop is idling */ -#define EV_PREPARE 0x00001000L /* event loop about to poll */ -#define EV_CHECK 0x00002000L /* event loop finished poll */ -#define EV_CHILD 0x00004000L /* child/pid had status change */ -#define EV_EMBED 0x00008000L /* embedded event loop needs sweep */ -#define EV_STAT 0x00010000L /* stat data changed */ +#define EV_CHILD 0x00000800L /* child/pid had status change */ +#define EV_STAT 0x00001000L /* stat data changed */ +#define EV_IDLE 0x00002000L /* event loop is idling */ +#define EV_PREPARE 0x00004000L /* event loop about to poll */ +#define EV_CHECK 0x00008000L /* event loop finished poll */ +#define EV_EMBED 0x00010000L /* embedded event loop needs sweep */ +#define EV_FORK 0x00020000L /* event loop resumed in child */ #define EV_ERROR 0x80000000L /* sent when an error occurs */ /* can be used to add custom fields to all watchers, while losing binary compatibility */ @@ -255,6 +260,14 @@ typedef struct ev_check EV_WATCHER (ev_check) } ev_check; +#if EV_FORK_ENABLE +/* the callback gets invoked before check in the child process when a fork was detected */ +typedef struct ev_fork +{ + EV_WATCHER (ev_fork) +} ev_fork; +#endif + #if EV_EMBED_ENABLE /* used to embed an event loop inside another */ /* the callback gets invoked when the event loop has handled events, and can be 0 */ @@ -276,6 +289,7 @@ union ev_any_watcher struct ev_io io; struct ev_timer timer; struct ev_periodic periodic; + struct ev_signal signal; struct ev_child child; #if EV_STAT_ENABLE struct ev_stat stat; @@ -283,7 +297,9 @@ union ev_any_watcher struct ev_idle idle; struct ev_prepare prepare; struct ev_check check; - struct ev_signal signal; +#if EV_FORK_ENABLE + struct ev_fork fork; +#endif #if EV_EMBED_ENABLE struct ev_embed embed; #endif @@ -413,6 +429,7 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent #define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */ #define ev_check_set(ev) /* nop, yes, this is a serious in-joke */ #define ev_embed_set(ev,loop_) do { (ev)->loop = (loop_); } while (0) +#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */ #define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0) #define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0) @@ -424,6 +441,7 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent #define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0) #define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0) #define ev_embed_init(ev,cb,loop) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(loop)); } while (0) +#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0) #define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ #define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ @@ -483,6 +501,11 @@ void ev_prepare_stop (EV_P_ ev_prepare *w); void ev_check_start (EV_P_ ev_check *w); void ev_check_stop (EV_P_ ev_check *w); +# if EV_FORK_ENABLE +void ev_fork_start (EV_P_ ev_fork *w); +void ev_fork_stop (EV_P_ ev_fork *w); +# endif + # if EV_EMBED_ENABLE /* only supported when loop to be embedded is in fact embeddable */ void ev_embed_start (EV_P_ ev_embed *w); diff --git a/ev.html b/ev.html index f643a6b..c5df51e 100644 --- a/ev.html +++ b/ev.html @@ -6,7 +6,7 @@ - + @@ -37,11 +37,13 @@
  • ev_idle - when you've got nothing better to do...
  • ev_prepare and ev_check - customise your event loop!
  • ev_embed - when one backend isn't enough...
  • +
  • ev_fork - the audacity to resume the event loop after a fork
  • OTHER FUNCTIONS
  • LIBEVENT EMULATION
  • C++ SUPPORT
  • +
  • MACRO MAGIC
  • EMBEDDING