summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2011-06-13 09:52:36 +0000
committerroot <root>2011-06-13 09:52:36 +0000
commit2d984ba58ba63b062436d51b1c3724fb31e33964 (patch)
treec78a821ae6beaa4802ab0b88d6d6f6bf4240ea45
parentf16fbd21ee467f0069e6e9c21be59ec41c9847af (diff)
*** empty log message ***
-rw-r--r--ev.c117
-rw-r--r--ev.pod42
-rw-r--r--ev_vars.h2
-rw-r--r--ev_wrap.h4
4 files changed, 99 insertions, 66 deletions
diff --git a/ev.c b/ev.c
index 6792e3f..b8dc960 100644
--- a/ev.c
+++ b/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)
+ 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);
}
diff --git a/ev.pod b/ev.pod
index 32e9479..ef5b4f6 100644
--- a/ev.pod
+++ b/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
diff --git a/ev_vars.h b/ev_vars.h
index 0f1fecf..db132cb 100644
--- a/ev_vars.h
+++ b/ev_vars.h
@@ -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)
diff --git a/ev_wrap.h b/ev_wrap.h
index 309be2f..2dd8bb4 100644
--- a/ev_wrap.h
+++ b/ev_wrap.h
@@ -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