mirror of /home/gitosis/repositories/libev.git
*** empty log message ***
This commit is contained in:
parent
20625c27b8
commit
5d7432532f
121
ev.c
121
ev.c
|
@ -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)
|
||||
{
|
||||
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);
|
||||
pipe_write_skipped = 1;
|
||||
|
||||
errno = old_errno;
|
||||
if (pipe_write_wanted)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
errno = old_errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1401,20 +1410,25 @@ pipecb (EV_P_ ev_io *iow, int revents)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (revents & EV_READ)
|
||||
{
|
||||
#if EV_USE_EVENTFD
|
||||
if (evfd >= 0)
|
||||
{
|
||||
uint64_t counter;
|
||||
read (evfd, &counter, sizeof (uint64_t));
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
|
42
ev.pod
42
ev.pod
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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…
Reference in New Issue