Browse Source

*** empty log message ***

master
Marc Alexander Lehmann 9 years ago
parent
commit
5d7432532f
4 changed files with 99 additions and 66 deletions
  1. +71
    -46
      ev.c
  2. +22
    -20
      ev.pod
  3. +2
    -0
      ev_vars.h
  4. +4
    -0
      ev_wrap.h

+ 71
- 46
ev.c View File

@ -1370,27 +1370,36 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
{
if (!*flag)
{
int old_errno = errno; /* save errno because write might clobber it */
char dummy;
*flag = 1;
#if EV_USE_EVENTFD
if (evfd >= 0)
pipe_write_skipped = 1;
if (pipe_write_wanted)
{
uint64_t counter = 1;
write (evfd, &counter, sizeof (uint64_t));
}
else
int old_errno = errno; /* save errno because write will clobber it */
char dummy;
pipe_write_skipped = 0;
#if EV_USE_EVENTFD
if (evfd >= 0)
{
uint64_t counter = 1;
write (evfd, &counter, sizeof (uint64_t));
}
else
#endif
/* win32 people keep sending patches that change this write() to send() */
/* and then run away. but send() is wrong, it wants a socket handle on win32 */
/* so when you think this write should be a send instead, please find out */
/* where your send() is from - it's definitely not the microsoft send, and */
/* tell me. thank you. */
write (evpipe [1], &dummy, 1);
{
/* win32 people keep sending patches that change this write() to send() */
/* and then run away. but send() is wrong, it wants a socket handle on win32 */
/* so when you think this write should be a send instead, please find out */
/* where your send() is from - it's definitely not the microsoft send, and */
/* tell me. thank you. */
write (evpipe [1], &dummy, 1);
}
errno = old_errno;
errno = old_errno;
}
}
}
@ -1401,20 +1410,25 @@ pipecb (EV_P_ ev_io *iow, int revents)
{
int i;
#if EV_USE_EVENTFD
if (evfd >= 0)
if (revents & EV_READ)
{
uint64_t counter;
read (evfd, &counter, sizeof (uint64_t));
}
else
#if EV_USE_EVENTFD
if (evfd >= 0)
{
uint64_t counter;
read (evfd, &counter, sizeof (uint64_t));
}
else
#endif
{
char dummy;
/* see discussion in evpipe_write when you think this read should be recv in win32 */
read (evpipe [0], &dummy, 1);
{
char dummy;
/* see discussion in evpipe_write when you think this read should be recv in win32 */
read (evpipe [0], &dummy, 1);
}
}
pipe_write_skipped = 0;
#if EV_SIGNAL_ENABLE
if (sig_pending)
{
@ -1453,6 +1467,8 @@ ev_feed_signal (int signum)
return;
#endif
evpipe_init (EV_A);
signals [signum - 1].pending = 1;
evpipe_write (EV_A_ &sig_pending);
}
@ -1759,27 +1775,29 @@ loop_init (EV_P_ unsigned int flags)
&& getenv ("LIBEV_FLAGS"))
flags = atoi (getenv ("LIBEV_FLAGS"));
ev_rt_now = ev_time ();
mn_now = get_clock ();
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
ev_rt_now = ev_time ();
mn_now = get_clock ();
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
#if EV_FEATURE_API
invoke_cb = ev_invoke_pending;
invoke_cb = ev_invoke_pending;
#endif
io_blocktime = 0.;
timeout_blocktime = 0.;
backend = 0;
backend_fd = -1;
sig_pending = 0;
io_blocktime = 0.;
timeout_blocktime = 0.;
backend = 0;
backend_fd = -1;
sig_pending = 0;
#if EV_ASYNC_ENABLE
async_pending = 0;
async_pending = 0;
#endif
pipe_write_skipped = 0;
pipe_write_wanted = 0;
#if EV_USE_INOTIFY
fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
#if EV_USE_SIGNALFD
sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
#endif
if (!(flags & EVBACKEND_MASK))
@ -1954,12 +1972,7 @@ loop_fork (EV_P)
if (ev_is_active (&pipe_w))
{
/* this "locks" the handlers against writing to the pipe */
/* while we modify the fd vars */
sig_pending = 1;
#if EV_ASYNC_ENABLE
async_pending = 1;
#endif
/* pipe_write_wanted must be false now, so modifying fd vars should be safe */
ev_ref (EV_A);
ev_io_stop (EV_A_ &pipe_w);
@ -2501,7 +2514,10 @@ ev_run (EV_P_ int flags)
/* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100);
if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
/* from now on, we want a pipe-wake-up */
pipe_write_wanted = 1;
if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
{
waittime = MAX_BLOCKTIME;
@ -2551,6 +2567,15 @@ ev_run (EV_P_ int flags)
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
pipe_write_wanted = 0;
if (pipe_write_skipped)
{
assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
}
/* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
}


+ 22
- 20
ev.pod View File

@ -610,11 +610,11 @@ hacks).
On the negative side, the interface is I<bizarre> - so bizarre that
even sun itself gets it wrong in their code examples: The event polling
function sometimes returning events to the caller even though an error
function sometimes returns events to the caller even though an error
occurred, but with no indication whether it has done so or not (yes, it's
even documented that way) - deadly for edge-triggered interfaces where
you absolutely have to know whether an event occurred or not because you
have to re-arm the watcher.
even documented that way) - deadly for edge-triggered interfaces where you
absolutely have to know whether an event occurred or not because you have
to re-arm the watcher.
Fortunately libev seems to be able to work around these idiocies.
@ -2025,7 +2025,7 @@ do stuff) the timer will not fire more than once per event loop iteration.
=item ev_timer_again (loop, ev_timer *)
This will act as if the timer timed out and restart it again if it is
This will act as if the timer timed out and restarts it again if it is
repeating. The exact semantics are:
If the timer is pending, its pending status is cleared.
@ -3222,9 +3222,6 @@ of "global async watchers" by using a watcher on an otherwise unused
signal, and C<ev_feed_signal> to signal this watcher from another thread,
even without knowing which loop owns the signal.
Unlike C<ev_signal> watchers, C<ev_async> works with any event loop, not
just the default loop.
=head3 Queueing
C<ev_async> does not support queueing of data in any way. The reason
@ -3333,13 +3330,16 @@ signal or similar contexts (see the discussion of C<EV_ATOMIC_T> in the
embedding section below on what exactly this means).
Note that, as with other watchers in libev, multiple events might get
compressed into a single callback invocation (another way to look at this
is that C<ev_async> watchers are level-triggered, set on C<ev_async_send>,
reset when the event loop detects that).
compressed into a single callback invocation (another way to look at
this is that C<ev_async> watchers are level-triggered: they are set on
C<ev_async_send>, reset when the event loop detects that).
This call incurs the overhead of a system call only once per event loop
iteration, so while the overhead might be noticeable, it doesn't apply to
repeated calls to C<ev_async_send> for the same event loop.
This call incurs the overhead of at most one extra system call per event
loop iteration, if the event loop is blocked, and no syscall at all if
the event loop (or your program) is processing events. That means that
repeated calls are basically free (there is no need to avoid calls for
performance reasons) and that the overhead becomes smaller (typically
zero) under load.
=item bool = ev_async_pending (ev_async *)
@ -4371,10 +4371,11 @@ indicate GNU/Linux + Glibc 2.4 or newer, otherwise disabled.
=item EV_ATOMIC_T
Libev requires an integer type (suitable for storing C<0> or C<1>) whose
access is atomic with respect to other threads or signal contexts. No such
type is easily found in the C language, so you can provide your own type
that you know is safe for your purposes. It is used both for signal handler "locking"
as well as for signal and thread safety in C<ev_async> watchers.
access is atomic and serialised with respect to other threads or signal
contexts. No such type is easily found in the C language, so you can
provide your own type that you know is safe for your purposes. It is used
both for signal handler "locking" as well as for signal and thread safety
in C<ev_async> watchers.
In the absence of this define, libev will use C<sig_atomic_t volatile>
(from F<signal.h>), which is usually good enough on most platforms.
@ -5122,8 +5123,9 @@ watchers becomes O(1) with respect to priority handling.
=item Processing signals: O(max_signal_number)
Sending involves a system call I<iff> there were no other C<ev_async_send>
calls in the current loop iteration. Checking for async and signal events
involves iterating over all running async watchers or all signal numbers.
calls in the current loop iteration and the loop is currently
blocked. Checking for async and signal events involves iterating over all
running async watchers or all signal numbers.
=back


+ 2
- 0
ev_vars.h View File

@ -73,6 +73,8 @@ VARx(int, evfd)
#endif
VAR (evpipe, int evpipe [2])
VARx(ev_io, pipe_w)
VARx(EV_ATOMIC_T, pipe_write_wanted)
VARx(EV_ATOMIC_T, pipe_write_skipped)
#if !defined(_WIN32) || EV_GENWRAP
VARx(pid_t, curpid)


+ 4
- 0
ev_wrap.h View File

@ -25,6 +25,8 @@
#define evfd ((loop)->evfd)
#define evpipe ((loop)->evpipe)
#define pipe_w ((loop)->pipe_w)
#define pipe_write_wanted ((loop)->pipe_write_wanted)
#define pipe_write_skipped ((loop)->pipe_write_skipped)
#define curpid ((loop)->curpid)
#define postfork ((loop)->postfork)
#define vec_ri ((loop)->vec_ri)
@ -122,6 +124,8 @@
#undef evfd
#undef evpipe
#undef pipe_w
#undef pipe_write_wanted
#undef pipe_write_skipped
#undef curpid
#undef postfork
#undef vec_ri


Loading…
Cancel
Save