*** empty log message ***

master
Marc Alexander Lehmann 2007-12-22 05:47:56 +00:00
parent d1c6178af7
commit 218d9dd768
8 changed files with 200 additions and 17 deletions

View File

@ -37,9 +37,12 @@ ev_prepare_stop
ev_recommended_backends
ev_ref
ev_set_allocator
ev_set_io_collect_interval
ev_set_syserr_cb
ev_set_timeout_collect_interval
ev_signal_start
ev_signal_stop
ev_sleep
ev_stat_start
ev_stat_stat
ev_stat_stop

48
ev.3
View File

@ -129,7 +129,7 @@
.\" ========================================================================
.\"
.IX Title "EV 1"
.TH EV 1 "2007-12-21" "perl v5.8.8" "User Contributed Perl Documentation"
.TH EV 1 "2007-12-22" "perl v5.8.8" "User Contributed Perl Documentation"
.SH "NAME"
libev \- a high performance full\-featured event loop written in C
.SH "SYNOPSIS"
@ -257,6 +257,11 @@ library in any way.
Returns the current time as libev would use it. Please note that the
\&\f(CW\*(C`ev_now\*(C'\fR function is usually faster and also often returns the timestamp
you actually want to know.
.IP "void ev_sleep (ev_tstamp interval)" 4
.IX Item "void ev_sleep (ev_tstamp interval)"
Sleep for the given interval: The current thread will be blocked until
either it is interrupted or the given time interval has passed. Basically
this is a subsecond-resolution \f(CW\*(C`sleep ()\*(C'\fR.
.IP "int ev_version_major ()" 4
.IX Item "int ev_version_major ()"
.PD 0
@ -465,7 +470,7 @@ but it scales phenomenally better. While poll and select usually scale
like O(total_fds) where n is the total number of fds (or the highest fd),
epoll scales either O(1) or O(active_fds). The epoll design has a number
of shortcomings, such as silently dropping events in some hard-to-detect
cases and rewuiring a syscall per fd change, no fork support and bad
cases and rewiring a syscall per fd change, no fork support and bad
support for dup:
.Sp
While stopping, setting and starting an I/O watcher in the same iteration
@ -726,6 +731,41 @@ Example: For some weird reason, unregister the above signal handler again.
\& ev_ref (loop);
\& ev_signal_stop (loop, &exitsig);
.Ve
.IP "ev_set_io_collect_interval (ev_tstamp interval)" 4
.IX Item "ev_set_io_collect_interval (ev_tstamp interval)"
.PD 0
.IP "ev_set_timeout_collect_interval (ev_tstamp interval)" 4
.IX Item "ev_set_timeout_collect_interval (ev_tstamp interval)"
.PD
These advanced functions influence the time that libev will spend waiting
for events. Both are by default \f(CW0\fR, meaning that libev will try to
invoke timer/periodic callbacks and I/O callbacks with minimum latency.
.Sp
Setting these to a higher value (the \f(CW\*(C`interval\*(C'\fR \fImust\fR be >= \f(CW0\fR)
allows libev to delay invocation of I/O and timer/periodic callbacks to
increase efficiency of loop iterations.
.Sp
The background is that sometimes your program runs just fast enough to
handle one (or very few) event(s) per loop iteration. While this makes
the program responsive, it also wastes a lot of \s-1CPU\s0 time to poll for new
events, especially with backends like \f(CW\*(C`select ()\*(C'\fR which have a high
overhead for the actual polling but can deliver many events at once.
.Sp
By setting a higher \fIio collect interval\fR you allow libev to spend more
time collecting I/O events, so you can handle more events per iteration,
at the cost of increasing latency. Timeouts (both \f(CW\*(C`ev_periodic\*(C'\fR and
\&\f(CW\*(C`ev_timer\*(C'\fR) will be not affected.
.Sp
Likewise, by setting a higher \fItimeout collect interval\fR you allow libev
to spend more time collecting timeouts, at the expense of increased
latency (the watcher callback will be called later). \f(CW\*(C`ev_io\*(C'\fR watchers
will not be affected.
.Sp
Many programs can usually benefit by setting the io collect interval to
a value near \f(CW0.1\fR or so, which is often enough for interactive servers
(of course not for games), likewise for timeouts. It usually doesn't make
much sense to set it to a lower value than \f(CW0.01\fR, as this approsaches
the timing granularity of most systems.
.SH "ANATOMY OF A WATCHER"
.IX Header "ANATOMY OF A WATCHER"
A watcher is a structure that you create and register to record your
@ -2503,6 +2543,10 @@ runtime if successful). Otherwise no use of the realtime clock option will
be attempted. This effectively replaces \f(CW\*(C`gettimeofday\*(C'\fR by \f(CW\*(C`clock_get
(CLOCK_REALTIME, ...)\*(C'\fR and will not normally affect correctness. See the
note about libraries in the description of \f(CW\*(C`EV_USE_MONOTONIC\*(C'\fR, though.
.IP "\s-1EV_USE_NANOSLEEP\s0" 4
.IX Item "EV_USE_NANOSLEEP"
If defined to be \f(CW1\fR, libev will assume that \f(CW\*(C`nanosleep ()\*(C'\fR is available
and will use it for delays. Otherwise it will use \f(CW\*(C`select ()\*(C'\fR.
.IP "\s-1EV_USE_SELECT\s0" 4
.IX Item "EV_USE_SELECT"
If undefined or defined to be \f(CW1\fR, libev will compile in support for the

91
ev.c
View File

@ -56,6 +56,14 @@ extern "C" {
# endif
# endif
# ifndef EV_USE_NANOSLEEP
# if HAVE_NANOSLEEP
# define EV_USE_NANOSLEEP 1
# else
# define EV_USE_NANOSLEEP 0
# endif
# endif
# ifndef EV_USE_SELECT
# if HAVE_SELECT && HAVE_SYS_SELECT_H
# define EV_USE_SELECT 1
@ -148,6 +156,10 @@ extern "C" {
# define EV_USE_REALTIME 0
#endif
#ifndef EV_USE_NANOSLEEP
# define EV_USE_NANOSLEEP 0
#endif
#ifndef EV_USE_SELECT
# define EV_USE_SELECT 1
#endif
@ -209,6 +221,12 @@ extern "C" {
# define EV_USE_INOTIFY 0
#endif
#if !EV_USE_NANOSLEEP
# ifndef _WIN32
# include <sys/select.h>
# endif
#endif
#if EV_USE_INOTIFY
# include <sys/inotify.h>
#endif
@ -410,6 +428,33 @@ ev_now (EV_P)
}
#endif
void
ev_sleep (ev_tstamp delay)
{
if (delay > 0.)
{
#if EV_USE_NANOSLEEP
struct timespec ts;
ts.tv_sec = (time_t)delay;
ts.tv_nsec = (long)((delay - (ev_tstamp)(ts.tv_sec)) * 1e9);
nanosleep (&ts, 0);
#elif defined(_WIN32)
Sleep (delay * 1e3);
#else
struct timeval tv;
tv.tv_sec = (time_t)delay;
tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6);
select (0, 0, 0, 0, &tv);
#endif
}
}
/*****************************************************************************/
int inline_size
array_nextsize (int elem, int cur, int cnt)
{
@ -944,6 +989,18 @@ ev_loop_count (EV_P)
return loop_count;
}
void
ev_set_io_collect_interval (EV_P_ ev_tstamp interval)
{
io_blocktime = interval;
}
void
ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval)
{
timeout_blocktime = interval;
}
static void noinline
loop_init (EV_P_ unsigned int flags)
{
@ -962,6 +1019,9 @@ loop_init (EV_P_ unsigned int flags)
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
io_blocktime = 0.;
timeout_blocktime = 0.;
/* pid check not overridable via env */
#ifndef _WIN32
if (flags & EVFLAG_FORKCHECK)
@ -1458,39 +1518,50 @@ ev_loop (EV_P_ int flags)
/* calculate blocking time */
{
ev_tstamp block;
ev_tstamp waittime = 0.;
ev_tstamp sleeptime = 0.;
if (expect_false (flags & EVLOOP_NONBLOCK || idleall || !activecnt))
block = 0.; /* do not block at all */
else
if (expect_true (!(flags & EVLOOP_NONBLOCK || idleall || !activecnt)))
{
/* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100);
block = MAX_BLOCKTIME;
waittime = MAX_BLOCKTIME;
if (timercnt)
{
ev_tstamp to = ((WT)timers [0])->at - mn_now + backend_fudge;
if (block > to) block = to;
if (waittime > to) waittime = to;
}
#if EV_PERIODIC_ENABLE
if (periodiccnt)
{
ev_tstamp to = ((WT)periodics [0])->at - ev_rt_now + backend_fudge;
if (block > to) block = to;
if (waittime > to) waittime = to;
}
#endif
if (expect_false (block < 0.)) block = 0.;
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime;
sleeptime = waittime - backend_fudge;
if (expect_true (sleeptime > io_blocktime))
sleeptime = io_blocktime;
if (sleeptime)
{
ev_sleep (sleeptime);
waittime -= sleeptime;
}
}
++loop_count;
backend_poll (EV_A_ block);
backend_poll (EV_A_ waittime);
/* update ev_rt_now, do magic */
time_update (EV_A_ block);
time_update (EV_A_ waittime + sleeptime);
}
/* queue pending timers and reschedule them */

8
ev.h
View File

@ -346,6 +346,7 @@ unsigned int ev_recommended_backends (void);
unsigned int ev_embeddable_backends (void);
ev_tstamp ev_time (void);
void ev_sleep (ev_tstamp delay); /* sleep for a while */
/* Sets the allocation function to use, works like realloc.
* It is used to allocate and free memory.
@ -403,8 +404,8 @@ void ev_default_destroy (void); /* destroy the default loop */
/* you can actually call it at any time, anywhere :) */
void ev_default_fork (void);
unsigned int ev_backend (EV_P);
unsigned int ev_loop_count (EV_P);
unsigned int ev_backend (EV_P); /* backend in use by loop */
unsigned int ev_loop_count (EV_P); /* number of loop iterations */
#endif
#define EVLOOP_NONBLOCK 1 /* do not block/wait */
@ -417,6 +418,9 @@ unsigned int ev_loop_count (EV_P);
void ev_loop (EV_P_ int flags);
void ev_unloop (EV_P_ int how); /* set to 1 to break out of event loop, set to 2 to break out of all event loops */
void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */
void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */
/*
* ref/unref can be used to add or remove a refcount on the mainloop. every watcher
* keeps one reference. if you have a long-runing watcher you never unregister that

45
ev.pod
View File

@ -117,6 +117,12 @@ Returns the current time as libev would use it. Please note that the
C<ev_now> function is usually faster and also often returns the timestamp
you actually want to know.
=item ev_sleep (ev_tstamp interval)
Sleep for the given interval: The current thread will be blocked until
either it is interrupted or the given time interval has passed. Basically
this is a subsecond-resolution C<sleep ()>.
=item int ev_version_major ()
=item int ev_version_minor ()
@ -571,6 +577,40 @@ Example: For some weird reason, unregister the above signal handler again.
ev_ref (loop);
ev_signal_stop (loop, &exitsig);
=item ev_set_io_collect_interval (loop, ev_tstamp interval)
=item ev_set_timeout_collect_interval (loop, ev_tstamp interval)
These advanced functions influence the time that libev will spend waiting
for events. Both are by default C<0>, meaning that libev will try to
invoke timer/periodic callbacks and I/O callbacks with minimum latency.
Setting these to a higher value (the C<interval> I<must> be >= C<0>)
allows libev to delay invocation of I/O and timer/periodic callbacks to
increase efficiency of loop iterations.
The background is that sometimes your program runs just fast enough to
handle one (or very few) event(s) per loop iteration. While this makes
the program responsive, it also wastes a lot of CPU time to poll for new
events, especially with backends like C<select ()> which have a high
overhead for the actual polling but can deliver many events at once.
By setting a higher I<io collect interval> you allow libev to spend more
time collecting I/O events, so you can handle more events per iteration,
at the cost of increasing latency. Timeouts (both C<ev_periodic> and
C<ev_timer>) will be not affected.
Likewise, by setting a higher I<timeout collect interval> you allow libev
to spend more time collecting timeouts, at the expense of increased
latency (the watcher callback will be called later). C<ev_io> watchers
will not be affected.
Many programs can usually benefit by setting the io collect interval to
a value near C<0.1> or so, which is often enough for interactive servers
(of course not for games), likewise for timeouts. It usually doesn't make
much sense to set it to a lower value than C<0.01>, as this approsaches
the timing granularity of most systems.
=back
@ -2299,6 +2339,11 @@ be attempted. This effectively replaces C<gettimeofday> by C<clock_get
(CLOCK_REALTIME, ...)> and will not normally affect correctness. See the
note about libraries in the description of C<EV_USE_MONOTONIC>, though.
=item EV_USE_NANOSLEEP
If defined to be C<1>, libev will assume that C<nanosleep ()> is available
and will use it for delays. Otherwise it will use C<select ()>.
=item EV_USE_SELECT
If undefined or defined to be C<1>, libev will compile in support for the

View File

@ -3,14 +3,18 @@
VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */
VARx(ev_tstamp, mn_now) /* monotonic clock "now" */
VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */
VARx(ev_tstamp, io_blocktime);
VARx(ev_tstamp, timeout_blocktime);
VARx(int, backend)
VARx(int, activecnt) /* total number of active events ("refcount") */
VARx(unsigned int, loop_count); /* total number of loop iterations/blocks */
VARx(int, backend_fd)
VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */
VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))
VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout))
VARx(int, backend_fd)
#if !defined(_WIN32) || EV_GENWRAP
VARx(pid_t, curpid)

View File

@ -4,13 +4,15 @@
#define now_floor ((loop)->now_floor)
#define mn_now ((loop)->mn_now)
#define rtmn_diff ((loop)->rtmn_diff)
#define io_blocktime ((loop)->io_blocktime)
#define timeout_blocktime ((loop)->timeout_blocktime)
#define backend ((loop)->backend)
#define activecnt ((loop)->activecnt)
#define loop_count ((loop)->loop_count)
#define backend_fd ((loop)->backend_fd)
#define backend_fudge ((loop)->backend_fudge)
#define backend_modify ((loop)->backend_modify)
#define backend_poll ((loop)->backend_poll)
#define backend_fd ((loop)->backend_fd)
#define curpid ((loop)->curpid)
#define postfork ((loop)->postfork)
#define vec_ri ((loop)->vec_ri)
@ -67,13 +69,15 @@
#undef now_floor
#undef mn_now
#undef rtmn_diff
#undef io_blocktime
#undef timeout_blocktime
#undef backend
#undef activecnt
#undef loop_count
#undef backend_fd
#undef backend_fudge
#undef backend_modify
#undef backend_poll
#undef backend_fd
#undef curpid
#undef postfork
#undef vec_ri

View File

@ -14,6 +14,14 @@ AC_CHECK_FUNC(clock_gettime, [], [
fi
])
AC_CHECK_FUNC(nanonsleep, [], [
if test -z "$LIBEV_M4_AVOID_LIBRT"; then
AC_CHECK_LIB(rt, nanonsleep)
unset ac_cv_func_nanonsleep
AC_CHECK_FUNCS(nanonsleep)
fi
])
AC_CHECK_LIB(m, ceil)