mirror of /home/gitosis/repositories/libev.git
add member documentation
This commit is contained in:
parent
159d84a97b
commit
298cb4c054
204
ev.3
204
ev.3
|
@ -129,7 +129,7 @@
|
|||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title ""<STANDARD INPUT>" 1"
|
||||
.TH "<STANDARD INPUT>" 1 "2007-11-26" "perl v5.8.8" "User Contributed Perl Documentation"
|
||||
.TH "<STANDARD INPUT>" 1 "2007-11-27" "perl v5.8.8" "User Contributed Perl Documentation"
|
||||
.SH "NAME"
|
||||
libev \- a high performance full\-featured event loop written in C
|
||||
.SH "SYNOPSIS"
|
||||
|
@ -686,6 +686,10 @@ The signal specified in the \f(CW\*(C`ev_signal\*(C'\fR watcher has been receive
|
|||
.el .IP "\f(CWEV_CHILD\fR" 4
|
||||
.IX Item "EV_CHILD"
|
||||
The pid specified in the \f(CW\*(C`ev_child\*(C'\fR watcher has received a status change.
|
||||
.ie n .IP """EV_STAT""" 4
|
||||
.el .IP "\f(CWEV_STAT\fR" 4
|
||||
.IX Item "EV_STAT"
|
||||
The path specified in the \f(CW\*(C`ev_stat\*(C'\fR watcher changed its attributes somehow.
|
||||
.ie n .IP """EV_IDLE""" 4
|
||||
.el .IP "\f(CWEV_IDLE\fR" 4
|
||||
.IX Item "EV_IDLE"
|
||||
|
@ -823,7 +827,17 @@ have been omitted....
|
|||
.SH "WATCHER TYPES"
|
||||
.IX Header "WATCHER TYPES"
|
||||
This section describes each watcher in detail, but will not repeat
|
||||
information given in the last section.
|
||||
information given in the last section. Any initialisation/set macros,
|
||||
functions and members specific to the watcher type are explained.
|
||||
.PP
|
||||
Members are additionally marked with either \fI[read\-only]\fR, meaning that,
|
||||
while the watcher is active, you can look at the member and expect some
|
||||
sensible content, but you must not modify it (you can modify it while the
|
||||
watcher is stopped to your hearts content), or \fI[read\-write]\fR, which
|
||||
means you can expect it to have some sensible content while the watcher
|
||||
is active, but you can also modify it. Modifying it may not do something
|
||||
sensible or take immediate effect (or do anything at all), but libev will
|
||||
not crash or malfunction in any way.
|
||||
.ie n .Sh """ev_io"" \- is this file descriptor readable or writable?"
|
||||
.el .Sh "\f(CWev_io\fP \- is this file descriptor readable or writable?"
|
||||
.IX Subsection "ev_io - is this file descriptor readable or writable?"
|
||||
|
@ -873,6 +887,12 @@ its own, so its quite safe to use).
|
|||
Configures an \f(CW\*(C`ev_io\*(C'\fR watcher. The \f(CW\*(C`fd\*(C'\fR is the file descriptor to
|
||||
rceeive events for and events is either \f(CW\*(C`EV_READ\*(C'\fR, \f(CW\*(C`EV_WRITE\*(C'\fR or
|
||||
\&\f(CW\*(C`EV_READ | EV_WRITE\*(C'\fR to receive the given events.
|
||||
.IP "int fd [read\-only]" 4
|
||||
.IX Item "int fd [read-only]"
|
||||
The file descriptor being watched.
|
||||
.IP "int events [read\-only]" 4
|
||||
.IX Item "int events [read-only]"
|
||||
The events being watched.
|
||||
.PP
|
||||
Example: call \f(CW\*(C`stdin_readable_cb\*(C'\fR when \s-1STDIN_FILENO\s0 has become, well
|
||||
readable, but only once. Since it is likely line\-buffered, you could
|
||||
|
@ -947,13 +967,36 @@ If the timer is repeating, either start it if necessary (with the repeat
|
|||
value), or reset the running timer to the repeat value.
|
||||
.Sp
|
||||
This sounds a bit complicated, but here is a useful and typical
|
||||
example: Imagine you have a tcp connection and you want a so-called idle
|
||||
timeout, that is, you want to be called when there have been, say, 60
|
||||
seconds of inactivity on the socket. The easiest way to do this is to
|
||||
configure an \f(CW\*(C`ev_timer\*(C'\fR with after=repeat=60 and calling ev_timer_again each
|
||||
time you successfully read or write some data. If you go into an idle
|
||||
state where you do not expect data to travel on the socket, you can stop
|
||||
the timer, and again will automatically restart it if need be.
|
||||
example: Imagine you have a tcp connection and you want a so-called
|
||||
idle timeout, that is, you want to be called when there have been,
|
||||
say, 60 seconds of inactivity on the socket. The easiest way to do
|
||||
this is to configure an \f(CW\*(C`ev_timer\*(C'\fR with \f(CW\*(C`after\*(C'\fR=\f(CW\*(C`repeat\*(C'\fR=\f(CW60\fR and calling
|
||||
\&\f(CW\*(C`ev_timer_again\*(C'\fR each time you successfully read or write some data. If
|
||||
you go into an idle state where you do not expect data to travel on the
|
||||
socket, you can stop the timer, and again will automatically restart it if
|
||||
need be.
|
||||
.Sp
|
||||
You can also ignore the \f(CW\*(C`after\*(C'\fR value and \f(CW\*(C`ev_timer_start\*(C'\fR altogether
|
||||
and only ever use the \f(CW\*(C`repeat\*(C'\fR value:
|
||||
.Sp
|
||||
.Vb 8
|
||||
\& ev_timer_init (timer, callback, 0., 5.);
|
||||
\& ev_timer_again (loop, timer);
|
||||
\& ...
|
||||
\& timer->again = 17.;
|
||||
\& ev_timer_again (loop, timer);
|
||||
\& ...
|
||||
\& timer->again = 10.;
|
||||
\& ev_timer_again (loop, timer);
|
||||
.Ve
|
||||
.Sp
|
||||
This is more efficient then stopping/starting the timer eahc time you want
|
||||
to modify its timeout value.
|
||||
.IP "ev_tstamp repeat [read\-write]" 4
|
||||
.IX Item "ev_tstamp repeat [read-write]"
|
||||
The current \f(CW\*(C`repeat\*(C'\fR value. Will be used each time the watcher times out
|
||||
or \f(CW\*(C`ev_timer_again\*(C'\fR is called and determines the next timeout (if any),
|
||||
which is also when any modifications are taken into account.
|
||||
.PP
|
||||
Example: create a timer that fires after 60 seconds.
|
||||
.PP
|
||||
|
@ -1095,6 +1138,16 @@ Simply stops and restarts the periodic watcher again. This is only useful
|
|||
when you changed some parameters or the reschedule callback would return
|
||||
a different time than the last time it was called (e.g. in a crond like
|
||||
program when the crontabs have changed).
|
||||
.IP "ev_tstamp interval [read\-write]" 4
|
||||
.IX Item "ev_tstamp interval [read-write]"
|
||||
The current interval value. Can be modified any time, but changes only
|
||||
take effect when the periodic timer fires or \f(CW\*(C`ev_periodic_again\*(C'\fR is being
|
||||
called.
|
||||
.IP "ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) [read\-write]" 4
|
||||
.IX Item "ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) [read-write]"
|
||||
The current reschedule callback, or \f(CW0\fR, if this functionality is
|
||||
switched off. Can be changed any time, but changes only take effect when
|
||||
the periodic timer fires or \f(CW\*(C`ev_periodic_again\*(C'\fR is being called.
|
||||
.PP
|
||||
Example: call a callback every hour, or, more precisely, whenever the
|
||||
system clock is divisible by 3600. The callback invocation times have
|
||||
|
@ -1162,6 +1215,9 @@ watcher for a signal is stopped libev will reset the signal handler to
|
|||
.PD
|
||||
Configures the watcher to trigger on the given signal number (usually one
|
||||
of the \f(CW\*(C`SIGxxx\*(C'\fR constants).
|
||||
.IP "int signum [read\-only]" 4
|
||||
.IX Item "int signum [read-only]"
|
||||
The signal the watcher watches out for.
|
||||
.ie n .Sh """ev_child"" \- watch out for process status changes"
|
||||
.el .Sh "\f(CWev_child\fP \- watch out for process status changes"
|
||||
.IX Subsection "ev_child - watch out for process status changes"
|
||||
|
@ -1179,6 +1235,16 @@ at the \f(CW\*(C`rstatus\*(C'\fR member of the \f(CW\*(C`ev_child\*(C'\fR watche
|
|||
the status word (use the macros from \f(CW\*(C`sys/wait.h\*(C'\fR and see your systems
|
||||
\&\f(CW\*(C`waitpid\*(C'\fR documentation). The \f(CW\*(C`rpid\*(C'\fR member contains the pid of the
|
||||
process causing the status change.
|
||||
.IP "int pid [read\-only]" 4
|
||||
.IX Item "int pid [read-only]"
|
||||
The process id this watcher watches out for, or \f(CW0\fR, meaning any process id.
|
||||
.IP "int rpid [read\-write]" 4
|
||||
.IX Item "int rpid [read-write]"
|
||||
The process id that detected a status change.
|
||||
.IP "int rstatus [read\-write]" 4
|
||||
.IX Item "int rstatus [read-write]"
|
||||
The process exit/trace status caused by \f(CW\*(C`rpid\*(C'\fR (see your systems
|
||||
\&\f(CW\*(C`waitpid\*(C'\fR and \f(CW\*(C`sys/wait.h\*(C'\fR documentation for details).
|
||||
.PP
|
||||
Example: try to exit cleanly on \s-1SIGINT\s0 and \s-1SIGTERM\s0.
|
||||
.PP
|
||||
|
@ -1195,6 +1261,101 @@ Example: try to exit cleanly on \s-1SIGINT\s0 and \s-1SIGTERM\s0.
|
|||
\& ev_signal_init (&signal_watcher, sigint_cb, SIGINT);
|
||||
\& ev_signal_start (loop, &sigint_cb);
|
||||
.Ve
|
||||
.ie n .Sh """ev_stat"" \- did the file attributes just change?"
|
||||
.el .Sh "\f(CWev_stat\fP \- did the file attributes just change?"
|
||||
.IX Subsection "ev_stat - did the file attributes just change?"
|
||||
This watches a filesystem path for attribute changes. That is, it calls
|
||||
\&\f(CW\*(C`stat\*(C'\fR regularly (or when the \s-1OS\s0 says it changed) and sees if it changed
|
||||
compared to the last time, invoking the callback if it did.
|
||||
.PP
|
||||
The path does not need to exist: changing from \*(L"path exists\*(R" to \*(L"path does
|
||||
not exist\*(R" is a status change like any other. The condition \*(L"path does
|
||||
not exist\*(R" is signified by the \f(CW\*(C`st_nlink\*(C'\fR field being zero (which is
|
||||
otherwise always forced to be at least one) and all the other fields of
|
||||
the stat buffer having unspecified contents.
|
||||
.PP
|
||||
Since there is no standard to do this, the portable implementation simply
|
||||
calls \f(CW\*(C`stat (2)\*(C'\fR regulalry on the path to see if it changed somehow. You
|
||||
can specify a recommended polling interval for this case. If you specify
|
||||
a polling interval of \f(CW0\fR (highly recommended!) then a \fIsuitable,
|
||||
unspecified default\fR value will be used (which you can expect to be around
|
||||
five seconds, although this might change dynamically). Libev will also
|
||||
impose a minimum interval which is currently around \f(CW0.1\fR, but thats
|
||||
usually overkill.
|
||||
.PP
|
||||
This watcher type is not meant for massive numbers of stat watchers,
|
||||
as even with OS-supported change notifications, this can be
|
||||
resource\-intensive.
|
||||
.PP
|
||||
At the time of this writing, no specific \s-1OS\s0 backends are implemented, but
|
||||
if demand increases, at least a kqueue and inotify backend will be added.
|
||||
.IP "ev_stat_init (ev_stat *, callback, const char *path, ev_tstamp interval)" 4
|
||||
.IX Item "ev_stat_init (ev_stat *, callback, const char *path, ev_tstamp interval)"
|
||||
.PD 0
|
||||
.IP "ev_stat_set (ev_stat *, const char *path, ev_tstamp interval)" 4
|
||||
.IX Item "ev_stat_set (ev_stat *, const char *path, ev_tstamp interval)"
|
||||
.PD
|
||||
Configures the watcher to wait for status changes of the given
|
||||
\&\f(CW\*(C`path\*(C'\fR. The \f(CW\*(C`interval\*(C'\fR is a hint on how quickly a change is expected to
|
||||
be detected and should normally be specified as \f(CW0\fR to let libev choose
|
||||
a suitable value. The memory pointed to by \f(CW\*(C`path\*(C'\fR must point to the same
|
||||
path for as long as the watcher is active.
|
||||
.Sp
|
||||
The callback will be receive \f(CW\*(C`EV_STAT\*(C'\fR when a change was detected,
|
||||
relative to the attributes at the time the watcher was started (or the
|
||||
last change was detected).
|
||||
.IP "ev_stat_stat (ev_stat *)" 4
|
||||
.IX Item "ev_stat_stat (ev_stat *)"
|
||||
Updates the stat buffer immediately with new values. If you change the
|
||||
watched path in your callback, you could call this fucntion to avoid
|
||||
detecting this change (while introducing a race condition). Can also be
|
||||
useful simply to find out the new values.
|
||||
.IP "ev_statdata attr [read\-only]" 4
|
||||
.IX Item "ev_statdata attr [read-only]"
|
||||
The most-recently detected attributes of the file. Although the type is of
|
||||
\&\f(CW\*(C`ev_statdata\*(C'\fR, this is usually the (or one of the) \f(CW\*(C`struct stat\*(C'\fR types
|
||||
suitable for your system. If the \f(CW\*(C`st_nlink\*(C'\fR member is \f(CW0\fR, then there
|
||||
was some error while \f(CW\*(C`stat\*(C'\fRing the file.
|
||||
.IP "ev_statdata prev [read\-only]" 4
|
||||
.IX Item "ev_statdata prev [read-only]"
|
||||
The previous attributes of the file. The callback gets invoked whenever
|
||||
\&\f(CW\*(C`prev\*(C'\fR != \f(CW\*(C`attr\*(C'\fR.
|
||||
.IP "ev_tstamp interval [read\-only]" 4
|
||||
.IX Item "ev_tstamp interval [read-only]"
|
||||
The specified interval.
|
||||
.IP "const char *path [read\-only]" 4
|
||||
.IX Item "const char *path [read-only]"
|
||||
The filesystem path that is being watched.
|
||||
.PP
|
||||
Example: Watch \f(CW\*(C`/etc/passwd\*(C'\fR for attribute changes.
|
||||
.PP
|
||||
.Vb 15
|
||||
\& static void
|
||||
\& passwd_cb (struct ev_loop *loop, ev_stat *w, int revents)
|
||||
\& {
|
||||
\& /* /etc/passwd changed in some way */
|
||||
\& if (w->attr.st_nlink)
|
||||
\& {
|
||||
\& printf ("passwd current size %ld\en", (long)w->attr.st_size);
|
||||
\& printf ("passwd current atime %ld\en", (long)w->attr.st_mtime);
|
||||
\& printf ("passwd current mtime %ld\en", (long)w->attr.st_mtime);
|
||||
\& }
|
||||
\& else
|
||||
\& /* you shalt not abuse printf for puts */
|
||||
\& puts ("wow, /etc/passwd is not there, expect problems. "
|
||||
\& "if this is windows, they already arrived\en");
|
||||
\& }
|
||||
.Ve
|
||||
.PP
|
||||
.Vb 2
|
||||
\& ...
|
||||
\& ev_stat passwd;
|
||||
.Ve
|
||||
.PP
|
||||
.Vb 2
|
||||
\& ev_stat_init (&passwd, passwd_cb, "/etc/passwd");
|
||||
\& ev_stat_start (loop, &passwd);
|
||||
.Ve
|
||||
.ie n .Sh """ev_idle"" \- when you've got nothing better to do..."
|
||||
.el .Sh "\f(CWev_idle\fP \- when you've got nothing better to do..."
|
||||
.IX Subsection "ev_idle - when you've got nothing better to do..."
|
||||
|
@ -1451,6 +1612,9 @@ if you do not want thta, you need to temporarily stop the embed watcher).
|
|||
Make a single, non-blocking sweep over the embedded loop. This works
|
||||
similarly to \f(CW\*(C`ev_loop (embedded_loop, EVLOOP_NONBLOCK)\*(C'\fR, but in the most
|
||||
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.
|
||||
.SH "OTHER FUNCTIONS"
|
||||
.IX Header "OTHER FUNCTIONS"
|
||||
There are some other functions of possible interest. Described. Here. Now.
|
||||
|
@ -1841,10 +2005,24 @@ will have the \f(CW\*(C`struct ev_loop *\*(C'\fR as first argument, and you can
|
|||
additional independent event loops. Otherwise there will be no support
|
||||
for multiple event loops and there is no first event loop pointer
|
||||
argument. Instead, all functions act on the single default loop.
|
||||
.IP "\s-1EV_PERIODICS\s0" 4
|
||||
.IX Item "EV_PERIODICS"
|
||||
If undefined or defined to be \f(CW1\fR, then periodic timers are supported,
|
||||
otherwise not. This saves a few kb of code.
|
||||
.IP "\s-1EV_PERIODIC_ENABLE\s0" 4
|
||||
.IX Item "EV_PERIODIC_ENABLE"
|
||||
If undefined or defined to be \f(CW1\fR, then periodic timers are supported. If
|
||||
defined to be \f(CW0\fR, then they are not. Disabling them saves a few kB of
|
||||
code.
|
||||
.IP "\s-1EV_EMBED_ENABLE\s0" 4
|
||||
.IX Item "EV_EMBED_ENABLE"
|
||||
If undefined or defined to be \f(CW1\fR, then embed watchers are supported. If
|
||||
defined to be \f(CW0\fR, then they are not.
|
||||
.IP "\s-1EV_STAT_ENABLE\s0" 4
|
||||
.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_MINIMAL\s0" 4
|
||||
.IX Item "EV_MINIMAL"
|
||||
If you need to shave off some kilobytes of code at the expense of some
|
||||
speed, define this symbol to \f(CW1\fR. Currently only used for gcc to override
|
||||
some inlining decisions, saves roughly 30% codesize of amd64.
|
||||
.IP "\s-1EV_COMMON\s0" 4
|
||||
.IX Item "EV_COMMON"
|
||||
By default, all watchers have a \f(CW\*(C`void *data\*(C'\fR member. By redefining
|
||||
|
|
276
ev.c
276
ev.c
|
@ -1560,6 +1560,144 @@ ev_periodic_again (EV_P_ ev_periodic *w)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
void
|
||||
ev_signal_start (EV_P_ ev_signal *w)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
assert (("signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
|
||||
#endif
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
assert (("ev_signal_start called with illegal signal number", w->signum > 0));
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
array_needsize (ANSIG, signals, signalmax, w->signum, signals_init);
|
||||
wlist_add ((WL *)&signals [w->signum - 1].head, (WL)w);
|
||||
|
||||
if (!((WL)w)->next)
|
||||
{
|
||||
#if _WIN32
|
||||
signal (w->signum, sighandler);
|
||||
#else
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sighandler;
|
||||
sigfillset (&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
|
||||
sigaction (w->signum, &sa, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ev_signal_stop (EV_P_ ev_signal *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
wlist_del ((WL *)&signals [w->signum - 1].head, (WL)w);
|
||||
ev_stop (EV_A_ (W)w);
|
||||
|
||||
if (!signals [w->signum - 1].head)
|
||||
signal (w->signum, SIG_DFL);
|
||||
}
|
||||
|
||||
void
|
||||
ev_child_start (EV_P_ ev_child *w)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
assert (("child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
|
||||
#endif
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
wlist_add ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w);
|
||||
}
|
||||
|
||||
void
|
||||
ev_child_stop (EV_P_ ev_child *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
wlist_del ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w);
|
||||
ev_stop (EV_A_ (W)w);
|
||||
}
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
|
||||
# ifdef _WIN32
|
||||
# define lstat(a,b) stat(a,b)
|
||||
# endif
|
||||
|
||||
#define DEF_STAT_INTERVAL 5.0074891
|
||||
#define MIN_STAT_INTERVAL 0.1074891
|
||||
|
||||
void
|
||||
ev_stat_stat (EV_P_ ev_stat *w)
|
||||
{
|
||||
if (lstat (w->path, &w->attr) < 0)
|
||||
w->attr.st_nlink = 0;
|
||||
else if (!w->attr.st_nlink)
|
||||
w->attr.st_nlink = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
stat_timer_cb (EV_P_ ev_timer *w_, int revents)
|
||||
{
|
||||
ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
|
||||
|
||||
/* we copy this here each the time so that */
|
||||
/* prev has the old value when the callback gets invoked */
|
||||
w->prev = w->attr;
|
||||
ev_stat_stat (EV_A_ w);
|
||||
|
||||
if (memcmp (&w->prev, &w->attr, sizeof (ev_statdata)))
|
||||
ev_feed_event (EV_A_ w, EV_STAT);
|
||||
}
|
||||
|
||||
void
|
||||
ev_stat_start (EV_P_ ev_stat *w)
|
||||
{
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
/* since we use memcmp, we need to clear any padding data etc. */
|
||||
memset (&w->prev, 0, sizeof (ev_statdata));
|
||||
memset (&w->attr, 0, sizeof (ev_statdata));
|
||||
|
||||
ev_stat_stat (EV_A_ w);
|
||||
|
||||
if (w->interval < MIN_STAT_INTERVAL)
|
||||
w->interval = w->interval ? MIN_STAT_INTERVAL : DEF_STAT_INTERVAL;
|
||||
|
||||
ev_timer_init (&w->timer, stat_timer_cb, w->interval, w->interval);
|
||||
ev_set_priority (&w->timer, ev_priority (w));
|
||||
ev_timer_start (EV_A_ &w->timer);
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
}
|
||||
|
||||
void
|
||||
ev_stat_stop (EV_P_ ev_stat *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
ev_timer_stop (EV_A_ &w->timer);
|
||||
|
||||
ev_stop (EV_A_ (W)w);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ev_idle_start (EV_P_ ev_idle *w)
|
||||
{
|
||||
|
@ -1641,77 +1779,6 @@ ev_check_stop (EV_P_ ev_check *w)
|
|||
ev_stop (EV_A_ (W)w);
|
||||
}
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
void
|
||||
ev_signal_start (EV_P_ ev_signal *w)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
assert (("signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
|
||||
#endif
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
assert (("ev_signal_start called with illegal signal number", w->signum > 0));
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
array_needsize (ANSIG, signals, signalmax, w->signum, signals_init);
|
||||
wlist_add ((WL *)&signals [w->signum - 1].head, (WL)w);
|
||||
|
||||
if (!((WL)w)->next)
|
||||
{
|
||||
#if _WIN32
|
||||
signal (w->signum, sighandler);
|
||||
#else
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sighandler;
|
||||
sigfillset (&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
|
||||
sigaction (w->signum, &sa, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ev_signal_stop (EV_P_ ev_signal *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
wlist_del ((WL *)&signals [w->signum - 1].head, (WL)w);
|
||||
ev_stop (EV_A_ (W)w);
|
||||
|
||||
if (!signals [w->signum - 1].head)
|
||||
signal (w->signum, SIG_DFL);
|
||||
}
|
||||
|
||||
void
|
||||
ev_child_start (EV_P_ ev_child *w)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
assert (("child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
|
||||
#endif
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
wlist_add ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w);
|
||||
}
|
||||
|
||||
void
|
||||
ev_child_stop (EV_P_ ev_child *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
wlist_del ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w);
|
||||
ev_stop (EV_A_ (W)w);
|
||||
}
|
||||
|
||||
#if EV_EMBED_ENABLE
|
||||
void noinline
|
||||
ev_embed_sweep (EV_P_ ev_embed *w)
|
||||
|
@ -1761,73 +1828,6 @@ ev_embed_stop (EV_P_ ev_embed *w)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
|
||||
# ifdef _WIN32
|
||||
# define lstat(a,b) stat(a,b)
|
||||
# endif
|
||||
|
||||
#define DEF_STAT_INTERVAL 5.0074891
|
||||
#define MIN_STAT_INTERVAL 0.1074891
|
||||
|
||||
void
|
||||
ev_stat_stat (EV_P_ ev_stat *w)
|
||||
{
|
||||
if (lstat (w->path, &w->attr) < 0)
|
||||
w->attr.st_nlink = 0;
|
||||
else if (!w->attr.st_nlink)
|
||||
w->attr.st_nlink = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
stat_timer_cb (EV_P_ ev_timer *w_, int revents)
|
||||
{
|
||||
ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
|
||||
|
||||
/* we copy this here each the time so that */
|
||||
/* prev has the old value when the callback gets invoked */
|
||||
w->prev = w->attr;
|
||||
ev_stat_stat (EV_A_ w);
|
||||
|
||||
if (memcmp (&w->prev, &w->attr, sizeof (ev_statdata)))
|
||||
ev_feed_event (EV_A_ w, EV_STAT);
|
||||
}
|
||||
|
||||
void
|
||||
ev_stat_start (EV_P_ ev_stat *w)
|
||||
{
|
||||
if (expect_false (ev_is_active (w)))
|
||||
return;
|
||||
|
||||
/* since we use memcmp, we need to clear any padding data etc. */
|
||||
memset (&w->prev, 0, sizeof (ev_statdata));
|
||||
memset (&w->attr, 0, sizeof (ev_statdata));
|
||||
|
||||
ev_stat_stat (EV_A_ w);
|
||||
|
||||
if (w->interval < MIN_STAT_INTERVAL)
|
||||
w->interval = w->interval ? MIN_STAT_INTERVAL : DEF_STAT_INTERVAL;
|
||||
|
||||
ev_timer_init (&w->timer, stat_timer_cb, w->interval, w->interval);
|
||||
ev_set_priority (&w->timer, ev_priority (w));
|
||||
ev_timer_start (EV_A_ &w->timer);
|
||||
|
||||
ev_start (EV_A_ (W)w, 1);
|
||||
}
|
||||
|
||||
void
|
||||
ev_stat_stop (EV_P_ ev_stat *w)
|
||||
{
|
||||
ev_clear_pending (EV_A_ (W)w);
|
||||
if (expect_false (!ev_is_active (w)))
|
||||
return;
|
||||
|
||||
ev_timer_stop (EV_A_ &w->timer);
|
||||
|
||||
ev_stop (EV_A_ (W)w);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct ev_once
|
||||
|
|
124
ev.h
124
ev.h
|
@ -161,6 +161,16 @@ typedef struct ev_watcher_time
|
|||
EV_WATCHER_TIME (ev_watcher_time)
|
||||
} ev_watcher_time;
|
||||
|
||||
/* invoked when fd is either EV_READable or EV_WRITEable */
|
||||
/* revent EV_READ, EV_WRITE */
|
||||
typedef struct ev_io
|
||||
{
|
||||
EV_WATCHER_LIST (ev_io)
|
||||
|
||||
int fd; /* ro */
|
||||
int events; /* ro */
|
||||
} ev_io;
|
||||
|
||||
/* invoked after a specific time, repeatable (based on monotonic clock) */
|
||||
/* revent EV_TIMEOUT */
|
||||
typedef struct ev_timer
|
||||
|
@ -180,16 +190,6 @@ typedef struct ev_periodic
|
|||
ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now); /* rw */
|
||||
} ev_periodic;
|
||||
|
||||
/* invoked when fd is either EV_READable or EV_WRITEable */
|
||||
/* revent EV_READ, EV_WRITE */
|
||||
typedef struct ev_io
|
||||
{
|
||||
EV_WATCHER_LIST (ev_io)
|
||||
|
||||
int fd; /* ro */
|
||||
int events; /* ro */
|
||||
} ev_io;
|
||||
|
||||
/* invoked when the given signal has been received */
|
||||
/* revent EV_SIGNAL */
|
||||
typedef struct ev_signal
|
||||
|
@ -199,6 +199,36 @@ typedef struct ev_signal
|
|||
int signum; /* ro */
|
||||
} ev_signal;
|
||||
|
||||
/* invoked when sigchld is received and waitpid indicates the given pid */
|
||||
/* revent EV_CHILD */
|
||||
/* does not support priorities */
|
||||
typedef struct ev_child
|
||||
{
|
||||
EV_WATCHER_LIST (ev_child)
|
||||
|
||||
int pid; /* ro */
|
||||
int rpid; /* rw, holds the received pid */
|
||||
int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */
|
||||
} ev_child;
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
/* st_nlink = 0 means missing file or other error */
|
||||
typedef struct stat ev_statdata;
|
||||
|
||||
/* invoked each time the stat data changes for a given path */
|
||||
/* revent EV_STAT */
|
||||
typedef struct ev_stat
|
||||
{
|
||||
EV_WATCHER (ev_stat)
|
||||
|
||||
ev_timer timer; /* private */
|
||||
ev_tstamp interval; /* ro */
|
||||
const char *path; /* ro */
|
||||
ev_statdata prev; /* ro */
|
||||
ev_statdata attr; /* ro */
|
||||
} ev_stat;
|
||||
#endif
|
||||
|
||||
/* invoked when the nothing else needs to be done, keeps the process from blocking */
|
||||
/* revent EV_IDLE */
|
||||
typedef struct ev_idle
|
||||
|
@ -221,18 +251,6 @@ typedef struct ev_check
|
|||
EV_WATCHER (ev_check)
|
||||
} ev_check;
|
||||
|
||||
/* invoked when sigchld is received and waitpid indicates the given pid */
|
||||
/* revent EV_CHILD */
|
||||
/* does not support priorities */
|
||||
typedef struct ev_child
|
||||
{
|
||||
EV_WATCHER_LIST (ev_child)
|
||||
|
||||
int pid; /* ro */
|
||||
int rpid; /* rw, holds the received pid */
|
||||
int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */
|
||||
} ev_child;
|
||||
|
||||
#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 */
|
||||
|
@ -245,24 +263,6 @@ typedef struct ev_embed
|
|||
} ev_embed;
|
||||
#endif
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
/* st_nlink = 0 means missing file or other error */
|
||||
typedef struct stat ev_statdata;
|
||||
|
||||
/* invoked each time the stat data changes for a given path */
|
||||
/* revent EV_STAT */
|
||||
typedef struct ev_stat
|
||||
{
|
||||
EV_WATCHER (ev_stat)
|
||||
|
||||
ev_timer timer; /* private */
|
||||
ev_tstamp interval; /* rw */
|
||||
const char *path; /* ro */
|
||||
ev_statdata prev; /* ro */
|
||||
ev_statdata attr; /* ro */
|
||||
} ev_stat;
|
||||
#endif
|
||||
|
||||
/* the presence of this union forces similar struct layout */
|
||||
union ev_any_watcher
|
||||
{
|
||||
|
@ -272,17 +272,17 @@ union ev_any_watcher
|
|||
struct ev_io io;
|
||||
struct ev_timer timer;
|
||||
struct ev_periodic periodic;
|
||||
struct ev_child child;
|
||||
#if EV_STAT_ENABLE
|
||||
struct ev_stat stat;
|
||||
#endif
|
||||
struct ev_idle idle;
|
||||
struct ev_prepare prepare;
|
||||
struct ev_check check;
|
||||
struct ev_signal signal;
|
||||
struct ev_child child;
|
||||
#if EV_EMBED_ENABLE
|
||||
struct ev_embed embed;
|
||||
#endif
|
||||
#if EV_STAT_ENABLE
|
||||
struct ev_stat stat;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* bits for ev_default_loop and ev_loop_new */
|
||||
|
@ -403,23 +403,23 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent
|
|||
#define ev_timer_set(ev,after_,repeat_) do { (ev)->at = (after_); (ev)->repeat = (repeat_); } while (0)
|
||||
#define ev_periodic_set(ev,at_,ival_,res_) do { (ev)->at = (at_); (ev)->interval = (ival_); (ev)->reschedule_cb= (res_); } while (0)
|
||||
#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0)
|
||||
#define ev_child_set(ev,pid_) do { (ev)->pid = (pid_); } while (0)
|
||||
#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); } while (0)
|
||||
#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#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_child_set(ev,pid_) do { (ev)->pid = (pid_); } while (0)
|
||||
#define ev_embed_set(ev,loop_) do { (ev)->loop = (loop_); } while (0)
|
||||
#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); } while (0)
|
||||
|
||||
#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)
|
||||
#define ev_periodic_init(ev,cb,at,ival,res) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(at),(ival),(res)); } while (0)
|
||||
#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0)
|
||||
#define ev_child_init(ev,cb,pid) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid)); } while (0)
|
||||
#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_path_set ((ev),(path),(interval)); } while (0)
|
||||
#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0)
|
||||
#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_child_init(ev,cb,pid) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid)); } while (0)
|
||||
#define ev_embed_init(ev,cb,loop) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(loop)); } while (0)
|
||||
#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_path_set ((ev),(path),(interval)); } 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 */
|
||||
|
@ -456,6 +456,20 @@ void ev_periodic_stop (EV_P_ ev_periodic *w);
|
|||
void ev_periodic_again (EV_P_ ev_periodic *w);
|
||||
#endif
|
||||
|
||||
/* only supported in the default loop */
|
||||
void ev_signal_start (EV_P_ ev_signal *w);
|
||||
void ev_signal_stop (EV_P_ ev_signal *w);
|
||||
|
||||
/* only supported in the default loop */
|
||||
void ev_child_start (EV_P_ ev_child *w);
|
||||
void ev_child_stop (EV_P_ ev_child *w);
|
||||
|
||||
# if EV_STAT_ENABLE
|
||||
void ev_stat_start (EV_P_ ev_stat *w);
|
||||
void ev_stat_stop (EV_P_ ev_stat *w);
|
||||
void ev_stat_stat (EV_P_ ev_stat *w);
|
||||
# endif
|
||||
|
||||
void ev_idle_start (EV_P_ ev_idle *w);
|
||||
void ev_idle_stop (EV_P_ ev_idle *w);
|
||||
|
||||
|
@ -465,14 +479,6 @@ 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);
|
||||
|
||||
/* only supported in the default loop */
|
||||
void ev_signal_start (EV_P_ ev_signal *w);
|
||||
void ev_signal_stop (EV_P_ ev_signal *w);
|
||||
|
||||
/* only supported in the default loop */
|
||||
void ev_child_start (EV_P_ ev_child *w);
|
||||
void ev_child_stop (EV_P_ ev_child *w);
|
||||
|
||||
# if EV_EMBED_ENABLE
|
||||
/* only supported when loop to be embedded is in fact embeddable */
|
||||
void ev_embed_start (EV_P_ ev_embed *w);
|
||||
|
@ -480,12 +486,6 @@ void ev_embed_stop (EV_P_ ev_embed *w);
|
|||
void ev_embed_sweep (EV_P_ ev_embed *w);
|
||||
# endif
|
||||
|
||||
# if EV_STAT_ENABLE
|
||||
void ev_stat_start (EV_P_ ev_stat *w);
|
||||
void ev_stat_stop (EV_P_ ev_stat *w);
|
||||
void ev_stat_stat (EV_P_ ev_stat *w);
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
210
ev.html
210
ev.html
|
@ -6,7 +6,7 @@
|
|||
<meta name="description" content="Pod documentation for libev" />
|
||||
<meta name="inputfile" content="<standard input>" />
|
||||
<meta name="outputfile" content="<standard output>" />
|
||||
<meta name="created" content="Mon Nov 26 11:20:35 2007" />
|
||||
<meta name="created" content="Tue Nov 27 09:11:42 2007" />
|
||||
<meta name="generator" content="Pod::Xhtml 1.57" />
|
||||
<link rel="stylesheet" href="http://res.tst.eu/pod.css"/></head>
|
||||
<body>
|
||||
|
@ -33,6 +33,7 @@
|
|||
<li><a href="#code_ev_periodic_code_to_cron_or_not"><code>ev_periodic</code> - to cron or not to cron?</a></li>
|
||||
<li><a href="#code_ev_signal_code_signal_me_when_a"><code>ev_signal</code> - signal me when a signal gets signalled!</a></li>
|
||||
<li><a href="#code_ev_child_code_watch_out_for_pro"><code>ev_child</code> - watch out for process status changes</a></li>
|
||||
<li><a href="#code_ev_stat_code_did_the_file_attri"><code>ev_stat</code> - did the file attributes just change?</a></li>
|
||||
<li><a href="#code_ev_idle_code_when_you_ve_got_no"><code>ev_idle</code> - when you've got nothing better to do...</a></li>
|
||||
<li><a href="#code_ev_prepare_code_and_code_ev_che"><code>ev_prepare</code> and <code>ev_check</code> - customise your event loop!</a></li>
|
||||
<li><a href="#code_ev_embed_code_when_one_backend_"><code>ev_embed</code> - when one backend isn't enough...</a></li>
|
||||
|
@ -588,6 +589,10 @@ writable.</p>
|
|||
<dd>
|
||||
<p>The pid specified in the <code>ev_child</code> watcher has received a status change.</p>
|
||||
</dd>
|
||||
<dt><code>EV_STAT</code></dt>
|
||||
<dd>
|
||||
<p>The path specified in the <code>ev_stat</code> watcher changed its attributes somehow.</p>
|
||||
</dd>
|
||||
<dt><code>EV_IDLE</code></dt>
|
||||
<dd>
|
||||
<p>The <code>ev_idle</code> watcher has determined that you have nothing better to do.</p>
|
||||
|
@ -734,7 +739,16 @@ have been omitted....</p>
|
|||
<h1 id="WATCHER_TYPES">WATCHER TYPES</h1><p><a href="#TOP" class="toplink">Top</a></p>
|
||||
<div id="WATCHER_TYPES_CONTENT">
|
||||
<p>This section describes each watcher in detail, but will not repeat
|
||||
information given in the last section.</p>
|
||||
information given in the last section. Any initialisation/set macros,
|
||||
functions and members specific to the watcher type are explained.</p>
|
||||
<p>Members are additionally marked with either <i>[read-only]</i>, meaning that,
|
||||
while the watcher is active, you can look at the member and expect some
|
||||
sensible content, but you must not modify it (you can modify it while the
|
||||
watcher is stopped to your hearts content), or <i>[read-write]</i>, which
|
||||
means you can expect it to have some sensible content while the watcher
|
||||
is active, but you can also modify it. Modifying it may not do something
|
||||
sensible or take immediate effect (or do anything at all), but libev will
|
||||
not crash or malfunction in any way.</p>
|
||||
|
||||
|
||||
|
||||
|
@ -783,6 +797,14 @@ its own, so its quite safe to use).</p>
|
|||
rceeive events for and events is either <code>EV_READ</code>, <code>EV_WRITE</code> or
|
||||
<code>EV_READ | EV_WRITE</code> to receive the given events.</p>
|
||||
</dd>
|
||||
<dt>int fd [read-only]</dt>
|
||||
<dd>
|
||||
<p>The file descriptor being watched.</p>
|
||||
</dd>
|
||||
<dt>int events [read-only]</dt>
|
||||
<dd>
|
||||
<p>The events being watched.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Example: call <code>stdin_readable_cb</code> when STDIN_FILENO has become, well
|
||||
readable, but only once. Since it is likely line-buffered, you could
|
||||
|
@ -849,13 +871,34 @@ repeating. The exact semantics are:</p>
|
|||
<p>If the timer is repeating, either start it if necessary (with the repeat
|
||||
value), or reset the running timer to the repeat value.</p>
|
||||
<p>This sounds a bit complicated, but here is a useful and typical
|
||||
example: Imagine you have a tcp connection and you want a so-called idle
|
||||
timeout, that is, you want to be called when there have been, say, 60
|
||||
seconds of inactivity on the socket. The easiest way to do this is to
|
||||
configure an <code>ev_timer</code> with after=repeat=60 and calling ev_timer_again each
|
||||
time you successfully read or write some data. If you go into an idle
|
||||
state where you do not expect data to travel on the socket, you can stop
|
||||
the timer, and again will automatically restart it if need be.</p>
|
||||
example: Imagine you have a tcp connection and you want a so-called
|
||||
idle timeout, that is, you want to be called when there have been,
|
||||
say, 60 seconds of inactivity on the socket. The easiest way to do
|
||||
this is to configure an <code>ev_timer</code> with <code>after</code>=<code>repeat</code>=<code>60</code> and calling
|
||||
<code>ev_timer_again</code> each time you successfully read or write some data. If
|
||||
you go into an idle state where you do not expect data to travel on the
|
||||
socket, you can stop the timer, and again will automatically restart it if
|
||||
need be.</p>
|
||||
<p>You can also ignore the <code>after</code> value and <code>ev_timer_start</code> altogether
|
||||
and only ever use the <code>repeat</code> value:</p>
|
||||
<pre> ev_timer_init (timer, callback, 0., 5.);
|
||||
ev_timer_again (loop, timer);
|
||||
...
|
||||
timer->again = 17.;
|
||||
ev_timer_again (loop, timer);
|
||||
...
|
||||
timer->again = 10.;
|
||||
ev_timer_again (loop, timer);
|
||||
|
||||
</pre>
|
||||
<p>This is more efficient then stopping/starting the timer eahc time you want
|
||||
to modify its timeout value.</p>
|
||||
</dd>
|
||||
<dt>ev_tstamp repeat [read-write]</dt>
|
||||
<dd>
|
||||
<p>The current <code>repeat</code> value. Will be used each time the watcher times out
|
||||
or <code>ev_timer_again</code> is called and determines the next timeout (if any),
|
||||
which is also when any modifications are taken into account.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Example: create a timer that fires after 60 seconds.</p>
|
||||
|
@ -983,6 +1026,18 @@ when you changed some parameters or the reschedule callback would return
|
|||
a different time than the last time it was called (e.g. in a crond like
|
||||
program when the crontabs have changed).</p>
|
||||
</dd>
|
||||
<dt>ev_tstamp interval [read-write]</dt>
|
||||
<dd>
|
||||
<p>The current interval value. Can be modified any time, but changes only
|
||||
take effect when the periodic timer fires or <code>ev_periodic_again</code> is being
|
||||
called.</p>
|
||||
</dd>
|
||||
<dt>ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) [read-write]</dt>
|
||||
<dd>
|
||||
<p>The current reschedule callback, or <code>0</code>, if this functionality is
|
||||
switched off. Can be changed any time, but changes only take effect when
|
||||
the periodic timer fires or <code>ev_periodic_again</code> is being called.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Example: call a callback every hour, or, more precisely, whenever the
|
||||
system clock is divisible by 3600. The callback invocation times have
|
||||
|
@ -1041,6 +1096,10 @@ SIG_DFL (regardless of what it was set to before).</p>
|
|||
<p>Configures the watcher to trigger on the given signal number (usually one
|
||||
of the <code>SIGxxx</code> constants).</p>
|
||||
</dd>
|
||||
<dt>int signum [read-only]</dt>
|
||||
<dd>
|
||||
<p>The signal the watcher watches out for.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
@ -1063,6 +1122,19 @@ the status word (use the macros from <code>sys/wait.h</code> and see your system
|
|||
<code>waitpid</code> documentation). The <code>rpid</code> member contains the pid of the
|
||||
process causing the status change.</p>
|
||||
</dd>
|
||||
<dt>int pid [read-only]</dt>
|
||||
<dd>
|
||||
<p>The process id this watcher watches out for, or <code>0</code>, meaning any process id.</p>
|
||||
</dd>
|
||||
<dt>int rpid [read-write]</dt>
|
||||
<dd>
|
||||
<p>The process id that detected a status change.</p>
|
||||
</dd>
|
||||
<dt>int rstatus [read-write]</dt>
|
||||
<dd>
|
||||
<p>The process exit/trace status caused by <code>rpid</code> (see your systems
|
||||
<code>waitpid</code> and <code>sys/wait.h</code> documentation for details).</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Example: try to exit cleanly on SIGINT and SIGTERM.</p>
|
||||
<pre> static void
|
||||
|
@ -1078,6 +1150,99 @@ process causing the status change.</p>
|
|||
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
<h2 id="code_ev_stat_code_did_the_file_attri"><code>ev_stat</code> - did the file attributes just change?</h2>
|
||||
<div id="code_ev_stat_code_did_the_file_attri-2">
|
||||
<p>This watches a filesystem path for attribute changes. That is, it calls
|
||||
<code>stat</code> regularly (or when the OS says it changed) and sees if it changed
|
||||
compared to the last time, invoking the callback if it did.</p>
|
||||
<p>The path does not need to exist: changing from "path exists" to "path does
|
||||
not exist" is a status change like any other. The condition "path does
|
||||
not exist" is signified by the <code>st_nlink</code> field being zero (which is
|
||||
otherwise always forced to be at least one) and all the other fields of
|
||||
the stat buffer having unspecified contents.</p>
|
||||
<p>Since there is no standard to do this, the portable implementation simply
|
||||
calls <code>stat (2)</code> regulalry on the path to see if it changed somehow. You
|
||||
can specify a recommended polling interval for this case. If you specify
|
||||
a polling interval of <code>0</code> (highly recommended!) then a <i>suitable,
|
||||
unspecified default</i> value will be used (which you can expect to be around
|
||||
five seconds, although this might change dynamically). Libev will also
|
||||
impose a minimum interval which is currently around <code>0.1</code>, but thats
|
||||
usually overkill.</p>
|
||||
<p>This watcher type is not meant for massive numbers of stat watchers,
|
||||
as even with OS-supported change notifications, this can be
|
||||
resource-intensive.</p>
|
||||
<p>At the time of this writing, no specific OS backends are implemented, but
|
||||
if demand increases, at least a kqueue and inotify backend will be added.</p>
|
||||
<dl>
|
||||
<dt>ev_stat_init (ev_stat *, callback, const char *path, ev_tstamp interval)</dt>
|
||||
<dt>ev_stat_set (ev_stat *, const char *path, ev_tstamp interval)</dt>
|
||||
<dd>
|
||||
<p>Configures the watcher to wait for status changes of the given
|
||||
<code>path</code>. The <code>interval</code> is a hint on how quickly a change is expected to
|
||||
be detected and should normally be specified as <code>0</code> to let libev choose
|
||||
a suitable value. The memory pointed to by <code>path</code> must point to the same
|
||||
path for as long as the watcher is active.</p>
|
||||
<p>The callback will be receive <code>EV_STAT</code> when a change was detected,
|
||||
relative to the attributes at the time the watcher was started (or the
|
||||
last change was detected).</p>
|
||||
</dd>
|
||||
<dt>ev_stat_stat (ev_stat *)</dt>
|
||||
<dd>
|
||||
<p>Updates the stat buffer immediately with new values. If you change the
|
||||
watched path in your callback, you could call this fucntion to avoid
|
||||
detecting this change (while introducing a race condition). Can also be
|
||||
useful simply to find out the new values.</p>
|
||||
</dd>
|
||||
<dt>ev_statdata attr [read-only]</dt>
|
||||
<dd>
|
||||
<p>The most-recently detected attributes of the file. Although the type is of
|
||||
<code>ev_statdata</code>, this is usually the (or one of the) <code>struct stat</code> types
|
||||
suitable for your system. If the <code>st_nlink</code> member is <code>0</code>, then there
|
||||
was some error while <code>stat</code>ing the file.</p>
|
||||
</dd>
|
||||
<dt>ev_statdata prev [read-only]</dt>
|
||||
<dd>
|
||||
<p>The previous attributes of the file. The callback gets invoked whenever
|
||||
<code>prev</code> != <code>attr</code>.</p>
|
||||
</dd>
|
||||
<dt>ev_tstamp interval [read-only]</dt>
|
||||
<dd>
|
||||
<p>The specified interval.</p>
|
||||
</dd>
|
||||
<dt>const char *path [read-only]</dt>
|
||||
<dd>
|
||||
<p>The filesystem path that is being watched.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Example: Watch <code>/etc/passwd</code> for attribute changes.</p>
|
||||
<pre> static void
|
||||
passwd_cb (struct ev_loop *loop, ev_stat *w, int revents)
|
||||
{
|
||||
/* /etc/passwd changed in some way */
|
||||
if (w->attr.st_nlink)
|
||||
{
|
||||
printf ("passwd current size %ld\n", (long)w->attr.st_size);
|
||||
printf ("passwd current atime %ld\n", (long)w->attr.st_mtime);
|
||||
printf ("passwd current mtime %ld\n", (long)w->attr.st_mtime);
|
||||
}
|
||||
else
|
||||
/* you shalt not abuse printf for puts */
|
||||
puts ("wow, /etc/passwd is not there, expect problems. "
|
||||
"if this is windows, they already arrived\n");
|
||||
}
|
||||
|
||||
...
|
||||
ev_stat passwd;
|
||||
|
||||
ev_stat_init (&passwd, passwd_cb, "/etc/passwd");
|
||||
ev_stat_start (loop, &passwd);
|
||||
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
|
@ -1306,6 +1471,10 @@ if you do not want thta, you need to temporarily stop the embed watcher).</p>
|
|||
similarly to <code>ev_loop (embedded_loop, EVLOOP_NONBLOCK)</code>, but in the most
|
||||
apropriate way for embedded loops.</p>
|
||||
</dd>
|
||||
<dt>struct ev_loop *loop [read-only]</dt>
|
||||
<dd>
|
||||
<p>The embedded event loop.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
@ -1704,10 +1873,27 @@ additional independent event loops. Otherwise there will be no support
|
|||
for multiple event loops and there is no first event loop pointer
|
||||
argument. Instead, all functions act on the single default loop.</p>
|
||||
</dd>
|
||||
<dt>EV_PERIODICS</dt>
|
||||
<dt>EV_PERIODIC_ENABLE</dt>
|
||||
<dd>
|
||||
<p>If undefined or defined to be <code>1</code>, then periodic timers are supported,
|
||||
otherwise not. This saves a few kb of code.</p>
|
||||
<p>If undefined or defined to be <code>1</code>, then periodic timers are supported. If
|
||||
defined to be <code>0</code>, then they are not. Disabling them saves a few kB of
|
||||
code.</p>
|
||||
</dd>
|
||||
<dt>EV_EMBED_ENABLE</dt>
|
||||
<dd>
|
||||
<p>If undefined or defined to be <code>1</code>, then embed watchers are supported. If
|
||||
defined to be <code>0</code>, then they are not.</p>
|
||||
</dd>
|
||||
<dt>EV_STAT_ENABLE</dt>
|
||||
<dd>
|
||||
<p>If undefined or defined to be <code>1</code>, then stat watchers are supported. If
|
||||
defined to be <code>0</code>, then they are not.</p>
|
||||
</dd>
|
||||
<dt>EV_MINIMAL</dt>
|
||||
<dd>
|
||||
<p>If you need to shave off some kilobytes of code at the expense of some
|
||||
speed, define this symbol to <code>1</code>. Currently only used for gcc to override
|
||||
some inlining decisions, saves roughly 30% codesize of amd64.</p>
|
||||
</dd>
|
||||
<dt>EV_COMMON</dt>
|
||||
<dd>
|
||||
|
|
191
ev.pod
191
ev.pod
|
@ -547,6 +547,10 @@ The signal specified in the C<ev_signal> watcher has been received by a thread.
|
|||
|
||||
The pid specified in the C<ev_child> watcher has received a status change.
|
||||
|
||||
=item C<EV_STAT>
|
||||
|
||||
The path specified in the C<ev_stat> watcher changed its attributes somehow.
|
||||
|
||||
=item C<EV_IDLE>
|
||||
|
||||
The C<ev_idle> watcher has determined that you have nothing better to do.
|
||||
|
@ -691,7 +695,17 @@ have been omitted....
|
|||
=head1 WATCHER TYPES
|
||||
|
||||
This section describes each watcher in detail, but will not repeat
|
||||
information given in the last section.
|
||||
information given in the last section. Any initialisation/set macros,
|
||||
functions and members specific to the watcher type are explained.
|
||||
|
||||
Members are additionally marked with either I<[read-only]>, meaning that,
|
||||
while the watcher is active, you can look at the member and expect some
|
||||
sensible content, but you must not modify it (you can modify it while the
|
||||
watcher is stopped to your hearts content), or I<[read-write]>, which
|
||||
means you can expect it to have some sensible content while the watcher
|
||||
is active, but you can also modify it. Modifying it may not do something
|
||||
sensible or take immediate effect (or do anything at all), but libev will
|
||||
not crash or malfunction in any way.
|
||||
|
||||
|
||||
=head2 C<ev_io> - is this file descriptor readable or writable?
|
||||
|
@ -744,6 +758,14 @@ Configures an C<ev_io> watcher. The C<fd> is the file descriptor to
|
|||
rceeive events for and events is either C<EV_READ>, C<EV_WRITE> or
|
||||
C<EV_READ | EV_WRITE> to receive the given events.
|
||||
|
||||
=item int fd [read-only]
|
||||
|
||||
The file descriptor being watched.
|
||||
|
||||
=item int events [read-only]
|
||||
|
||||
The events being watched.
|
||||
|
||||
=back
|
||||
|
||||
Example: call C<stdin_readable_cb> when STDIN_FILENO has become, well
|
||||
|
@ -816,13 +838,35 @@ If the timer is repeating, either start it if necessary (with the repeat
|
|||
value), or reset the running timer to the repeat value.
|
||||
|
||||
This sounds a bit complicated, but here is a useful and typical
|
||||
example: Imagine you have a tcp connection and you want a so-called idle
|
||||
timeout, that is, you want to be called when there have been, say, 60
|
||||
seconds of inactivity on the socket. The easiest way to do this is to
|
||||
configure an C<ev_timer> with after=repeat=60 and calling ev_timer_again each
|
||||
time you successfully read or write some data. If you go into an idle
|
||||
state where you do not expect data to travel on the socket, you can stop
|
||||
the timer, and again will automatically restart it if need be.
|
||||
example: Imagine you have a tcp connection and you want a so-called
|
||||
idle timeout, that is, you want to be called when there have been,
|
||||
say, 60 seconds of inactivity on the socket. The easiest way to do
|
||||
this is to configure an C<ev_timer> with C<after>=C<repeat>=C<60> and calling
|
||||
C<ev_timer_again> each time you successfully read or write some data. If
|
||||
you go into an idle state where you do not expect data to travel on the
|
||||
socket, you can stop the timer, and again will automatically restart it if
|
||||
need be.
|
||||
|
||||
You can also ignore the C<after> value and C<ev_timer_start> altogether
|
||||
and only ever use the C<repeat> value:
|
||||
|
||||
ev_timer_init (timer, callback, 0., 5.);
|
||||
ev_timer_again (loop, timer);
|
||||
...
|
||||
timer->again = 17.;
|
||||
ev_timer_again (loop, timer);
|
||||
...
|
||||
timer->again = 10.;
|
||||
ev_timer_again (loop, timer);
|
||||
|
||||
This is more efficient then stopping/starting the timer eahc time you want
|
||||
to modify its timeout value.
|
||||
|
||||
=item ev_tstamp repeat [read-write]
|
||||
|
||||
The current C<repeat> value. Will be used each time the watcher times out
|
||||
or C<ev_timer_again> is called and determines the next timeout (if any),
|
||||
which is also when any modifications are taken into account.
|
||||
|
||||
=back
|
||||
|
||||
|
@ -959,6 +1003,18 @@ when you changed some parameters or the reschedule callback would return
|
|||
a different time than the last time it was called (e.g. in a crond like
|
||||
program when the crontabs have changed).
|
||||
|
||||
=item ev_tstamp interval [read-write]
|
||||
|
||||
The current interval value. Can be modified any time, but changes only
|
||||
take effect when the periodic timer fires or C<ev_periodic_again> is being
|
||||
called.
|
||||
|
||||
=item ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) [read-write]
|
||||
|
||||
The current reschedule callback, or C<0>, if this functionality is
|
||||
switched off. Can be changed any time, but changes only take effect when
|
||||
the periodic timer fires or C<ev_periodic_again> is being called.
|
||||
|
||||
=back
|
||||
|
||||
Example: call a callback every hour, or, more precisely, whenever the
|
||||
|
@ -1018,6 +1074,10 @@ SIG_DFL (regardless of what it was set to before).
|
|||
Configures the watcher to trigger on the given signal number (usually one
|
||||
of the C<SIGxxx> constants).
|
||||
|
||||
=item int signum [read-only]
|
||||
|
||||
The signal the watcher watches out for.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
@ -1039,6 +1099,19 @@ the status word (use the macros from C<sys/wait.h> and see your systems
|
|||
C<waitpid> documentation). The C<rpid> member contains the pid of the
|
||||
process causing the status change.
|
||||
|
||||
=item int pid [read-only]
|
||||
|
||||
The process id this watcher watches out for, or C<0>, meaning any process id.
|
||||
|
||||
=item int rpid [read-write]
|
||||
|
||||
The process id that detected a status change.
|
||||
|
||||
=item int rstatus [read-write]
|
||||
|
||||
The process exit/trace status caused by C<rpid> (see your systems
|
||||
C<waitpid> and C<sys/wait.h> documentation for details).
|
||||
|
||||
=back
|
||||
|
||||
Example: try to exit cleanly on SIGINT and SIGTERM.
|
||||
|
@ -1054,6 +1127,104 @@ Example: try to exit cleanly on SIGINT and SIGTERM.
|
|||
ev_signal_start (loop, &sigint_cb);
|
||||
|
||||
|
||||
=head2 C<ev_stat> - did the file attributes just change?
|
||||
|
||||
This watches a filesystem path for attribute changes. That is, it calls
|
||||
C<stat> regularly (or when the OS says it changed) and sees if it changed
|
||||
compared to the last time, invoking the callback if it did.
|
||||
|
||||
The path does not need to exist: changing from "path exists" to "path does
|
||||
not exist" is a status change like any other. The condition "path does
|
||||
not exist" is signified by the C<st_nlink> field being zero (which is
|
||||
otherwise always forced to be at least one) and all the other fields of
|
||||
the stat buffer having unspecified contents.
|
||||
|
||||
Since there is no standard to do this, the portable implementation simply
|
||||
calls C<stat (2)> regulalry on the path to see if it changed somehow. You
|
||||
can specify a recommended polling interval for this case. If you specify
|
||||
a polling interval of C<0> (highly recommended!) then a I<suitable,
|
||||
unspecified default> value will be used (which you can expect to be around
|
||||
five seconds, although this might change dynamically). Libev will also
|
||||
impose a minimum interval which is currently around C<0.1>, but thats
|
||||
usually overkill.
|
||||
|
||||
This watcher type is not meant for massive numbers of stat watchers,
|
||||
as even with OS-supported change notifications, this can be
|
||||
resource-intensive.
|
||||
|
||||
At the time of this writing, no specific OS backends are implemented, but
|
||||
if demand increases, at least a kqueue and inotify backend will be added.
|
||||
|
||||
=over 4
|
||||
|
||||
=item ev_stat_init (ev_stat *, callback, const char *path, ev_tstamp interval)
|
||||
|
||||
=item ev_stat_set (ev_stat *, const char *path, ev_tstamp interval)
|
||||
|
||||
Configures the watcher to wait for status changes of the given
|
||||
C<path>. The C<interval> is a hint on how quickly a change is expected to
|
||||
be detected and should normally be specified as C<0> to let libev choose
|
||||
a suitable value. The memory pointed to by C<path> must point to the same
|
||||
path for as long as the watcher is active.
|
||||
|
||||
The callback will be receive C<EV_STAT> when a change was detected,
|
||||
relative to the attributes at the time the watcher was started (or the
|
||||
last change was detected).
|
||||
|
||||
=item ev_stat_stat (ev_stat *)
|
||||
|
||||
Updates the stat buffer immediately with new values. If you change the
|
||||
watched path in your callback, you could call this fucntion to avoid
|
||||
detecting this change (while introducing a race condition). Can also be
|
||||
useful simply to find out the new values.
|
||||
|
||||
=item ev_statdata attr [read-only]
|
||||
|
||||
The most-recently detected attributes of the file. Although the type is of
|
||||
C<ev_statdata>, this is usually the (or one of the) C<struct stat> types
|
||||
suitable for your system. If the C<st_nlink> member is C<0>, then there
|
||||
was some error while C<stat>ing the file.
|
||||
|
||||
=item ev_statdata prev [read-only]
|
||||
|
||||
The previous attributes of the file. The callback gets invoked whenever
|
||||
C<prev> != C<attr>.
|
||||
|
||||
=item ev_tstamp interval [read-only]
|
||||
|
||||
The specified interval.
|
||||
|
||||
=item const char *path [read-only]
|
||||
|
||||
The filesystem path that is being watched.
|
||||
|
||||
=back
|
||||
|
||||
Example: Watch C</etc/passwd> for attribute changes.
|
||||
|
||||
static void
|
||||
passwd_cb (struct ev_loop *loop, ev_stat *w, int revents)
|
||||
{
|
||||
/* /etc/passwd changed in some way */
|
||||
if (w->attr.st_nlink)
|
||||
{
|
||||
printf ("passwd current size %ld\n", (long)w->attr.st_size);
|
||||
printf ("passwd current atime %ld\n", (long)w->attr.st_mtime);
|
||||
printf ("passwd current mtime %ld\n", (long)w->attr.st_mtime);
|
||||
}
|
||||
else
|
||||
/* you shalt not abuse printf for puts */
|
||||
puts ("wow, /etc/passwd is not there, expect problems. "
|
||||
"if this is windows, they already arrived\n");
|
||||
}
|
||||
|
||||
...
|
||||
ev_stat passwd;
|
||||
|
||||
ev_stat_init (&passwd, passwd_cb, "/etc/passwd");
|
||||
ev_stat_start (loop, &passwd);
|
||||
|
||||
|
||||
=head2 C<ev_idle> - when you've got nothing better to do...
|
||||
|
||||
Idle watchers trigger events when there are no other events are pending
|
||||
|
@ -1294,6 +1465,10 @@ Make a single, non-blocking sweep over the embedded loop. This works
|
|||
similarly to C<ev_loop (embedded_loop, EVLOOP_NONBLOCK)>, but in the most
|
||||
apropriate way for embedded loops.
|
||||
|
||||
=item struct ev_loop *loop [read-only]
|
||||
|
||||
The embedded event loop.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue