/**/
+/*
+ * This is used to avoid floating point rounding problems.
+ * It is added to ev_rt_now when scheduling periodics
+ * to ensure progress, time-wise, even when rounding
+ * errors are against us.
+ * This value is good at least till the year 4000.
+ * Better solutions welcome.
+ */
+#define TIME_EPSILON 0.0001220703125 /* 1/8192 */
+
#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
#define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */
-/*#define CLEANUP_INTERVAL (MAX_BLOCKTIME * 5.) /* how often to try to free memory and re-check fds */
+/*#define CLEANUP_INTERVAL (MAX_BLOCKTIME * 5.) /* how often to try to free memory and re-check fds, TODO */
#if __GNUC__ >= 3
# define expect(expr,value) __builtin_expect ((expr),(value))
-# define inline_size static inline /* inline for codesize */
-# if EV_MINIMAL
-# define noinline __attribute__ ((noinline))
-# define inline_speed static noinline
-# else
-# define noinline
-# define inline_speed static inline
-# endif
+# define noinline __attribute__ ((noinline))
#else
# define expect(expr,value) (expr)
-# define inline_speed static
-# define inline_size static
# define noinline
+# if __STDC_VERSION__ < 199901L
+# define inline
+# endif
#endif
#define expect_false(expr) expect ((expr) != 0, 0)
#define expect_true(expr) expect ((expr) != 0, 1)
+#define inline_size static inline
+
+#if EV_MINIMAL
+# define inline_speed static noinline
+#else
+# define inline_speed static inline
+#endif
#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
-#define ABSPRI(w) ((w)->priority - EV_MINPRI)
+#define ABSPRI(w) (((W)w)->priority - EV_MINPRI)
-#define EMPTY0 /* required for microsofts broken pseudo-c compiler */
+#define EMPTY /* required for microsofts broken pseudo-c compiler */
#define EMPTY2(a,b) /* used to suppress some warnings */
typedef ev_watcher *W;
return ncur;
}
-inline_speed void *
+static noinline void *
array_realloc (int elem, void *base, int *cur, int cnt)
{
*cur = array_nextsize (elem, *cur, cnt);
ev_feed_event (EV_P_ void *w, int revents)
{
W w_ = (W)w;
+ int pri = ABSPRI (w_);
if (expect_false (w_->pending))
+ pendings [pri][w_->pending - 1].events |= revents;
+ else
{
- pendings [ABSPRI (w_)][w_->pending - 1].events |= revents;
- return;
+ w_->pending = ++pendingcnt [pri];
+ array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2);
+ pendings [pri][w_->pending - 1].w = w_;
+ pendings [pri][w_->pending - 1].events = revents;
}
-
- w_->pending = ++pendingcnt [ABSPRI (w_)];
- array_needsize (ANPENDING, pendings [ABSPRI (w_)], pendingmax [ABSPRI (w_)], pendingcnt [ABSPRI (w_)], EMPTY2);
- pendings [ABSPRI (w_)][w_->pending - 1].w = w_;
- pendings [ABSPRI (w_)][w_->pending - 1].events = revents;
}
void inline_size
void
ev_feed_fd_event (EV_P_ int fd, int revents)
{
- fd_event (EV_A_ fd, revents);
+ if (fd >= 0 && fd < anfdmax)
+ fd_event (EV_A_ fd, revents);
}
void inline_size
ev_feed_signal_event (EV_A_ signum + 1);
}
-void inline_size
+void inline_speed
fd_intern (int fd)
{
#ifdef _WIN32
for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
if (w->pid == pid || !w->pid)
{
- ev_priority (w) = ev_priority (sw); /* need to do it *now* */
- w->rpid = pid;
- w->rstatus = status;
+ ev_set_priority (w, ev_priority (sw)); /* need to do it *now* */
+ w->rpid = pid;
+ w->rstatus = status;
ev_feed_event (EV_A_ (W)w, EV_CHILD);
}
}
#endif
for (i = NUMPRI; i--; )
- array_free (pending, [i]);
+ {
+ array_free (pending, [i]);
+#if EV_IDLE_ENABLE
+ array_free (idle, [i]);
+#endif
+ }
/* have to use the microsoft-never-gets-it-right macro */
- array_free (fdchange, EMPTY0);
- array_free (timer, EMPTY0);
+ array_free (fdchange, EMPTY);
+ array_free (timer, EMPTY);
#if EV_PERIODIC_ENABLE
- array_free (periodic, EMPTY0);
+ array_free (periodic, EMPTY);
#endif
- array_free (idle, EMPTY0);
- array_free (prepare, EMPTY0);
- array_free (check, EMPTY0);
+ array_free (prepare, EMPTY);
+ array_free (check, EMPTY);
backend = 0;
}
/*****************************************************************************/
-int inline_size
-any_pending (EV_P)
+void
+ev_invoke (EV_P_ void *w, int revents)
{
- int pri;
-
- for (pri = NUMPRI; pri--; )
- if (pendingcnt [pri])
- return 1;
-
- return 0;
+ EV_CB_INVOKE ((W)w, revents);
}
void inline_speed
/* first reschedule or stop timer */
if (w->reschedule_cb)
{
- ((WT)w)->at = w->reschedule_cb (w, ev_rt_now + 0.0001);
+ ((WT)w)->at = w->reschedule_cb (w, ev_rt_now + TIME_EPSILON);
assert (("ev_periodic reschedule callback returned time in the past", ((WT)w)->at > ev_rt_now));
downheap ((WT *)periodics, periodiccnt, 0);
}
else if (w->interval)
{
- ((WT)w)->at += floor ((ev_rt_now - ((WT)w)->at) / w->interval + 1.) * w->interval;
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
+ if (((WT)w)->at - ev_rt_now <= TIME_EPSILON) ((WT)w)->at += w->interval;
assert (("ev_periodic timeout in the past detected while processing timers, negative interval?", ((WT)w)->at > ev_rt_now));
downheap ((WT *)periodics, periodiccnt, 0);
}
if (w->reschedule_cb)
((WT)w)->at = w->reschedule_cb (w, ev_rt_now);
else if (w->interval)
- ((WT)w)->at += ceil ((ev_rt_now - ((WT)w)->at) / w->interval) * w->interval;
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
}
/* now rebuild the heap */
}
#endif
-int inline_size
-time_update_monotonic (EV_P)
+#if EV_IDLE_ENABLE
+void inline_size
+idle_reify (EV_P)
{
- mn_now = get_clock ();
-
- if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5))
+ if (expect_false (idleall))
{
- ev_rt_now = rtmn_diff + mn_now;
- return 0;
- }
- else
- {
- now_floor = mn_now;
- ev_rt_now = ev_time ();
- return 1;
+ int pri;
+
+ for (pri = NUMPRI; pri--; )
+ {
+ if (pendingcnt [pri])
+ break;
+
+ if (idlecnt [pri])
+ {
+ queue_events (EV_A_ (W *)idles [pri], idlecnt [pri], EV_IDLE);
+ break;
+ }
+ }
}
}
+#endif
-void inline_size
-time_update (EV_P)
+void inline_speed
+time_update (EV_P_ ev_tstamp max_block)
{
int i;
#if EV_USE_MONOTONIC
if (expect_true (have_monotonic))
{
- if (time_update_monotonic (EV_A))
+ ev_tstamp odiff = rtmn_diff;
+
+ mn_now = get_clock ();
+
+ /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */
+ /* interpolate in the meantime */
+ if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5))
{
- ev_tstamp odiff = rtmn_diff;
-
- /* loop a few times, before making important decisions.
- * on the choice of "4": one iteration isn't enough,
- * in case we get preempted during the calls to
- * ev_time and get_clock. a second call is almost guaranteed
- * to succeed in that case, though. and looping a few more times
- * doesn't hurt either as we only do this on time-jumps or
- * in the unlikely event of having been preempted here.
- */
- for (i = 4; --i; )
- {
- rtmn_diff = ev_rt_now - mn_now;
+ ev_rt_now = rtmn_diff + mn_now;
+ return;
+ }
- if (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP)
- return; /* all is well */
+ now_floor = mn_now;
+ ev_rt_now = ev_time ();
- ev_rt_now = ev_time ();
- mn_now = get_clock ();
- now_floor = mn_now;
- }
+ /* loop a few times, before making important decisions.
+ * on the choice of "4": one iteration isn't enough,
+ * in case we get preempted during the calls to
+ * ev_time and get_clock. a second call is almost guaranteed
+ * to succeed in that case, though. and looping a few more times
+ * doesn't hurt either as we only do this on time-jumps or
+ * in the unlikely event of having been preempted here.
+ */
+ for (i = 4; --i; )
+ {
+ rtmn_diff = ev_rt_now - mn_now;
+
+ if (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP)
+ return; /* all is well */
+
+ ev_rt_now = ev_time ();
+ mn_now = get_clock ();
+ now_floor = mn_now;
+ }
# if EV_PERIODIC_ENABLE
- periodics_reschedule (EV_A);
+ periodics_reschedule (EV_A);
# endif
- /* no timer adjustment, as the monotonic clock doesn't jump */
- /* timers_reschedule (EV_A_ rtmn_diff - odiff) */
- }
+ /* no timer adjustment, as the monotonic clock doesn't jump */
+ /* timers_reschedule (EV_A_ rtmn_diff - odiff) */
}
else
#endif
{
ev_rt_now = ev_time ();
- if (expect_false (mn_now > ev_rt_now || mn_now < ev_rt_now - MAX_BLOCKTIME - MIN_TIMEJUMP))
+ if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP))
{
#if EV_PERIODIC_ENABLE
periodics_reschedule (EV_A);
#endif
-
/* adjust timers. this is easy, as the offset is the same for all of them */
for (i = 0; i < timercnt; ++i)
((WT)timers [i])->at += ev_rt_now - mn_now;
}
#endif
- /* queue check watchers (and execute them) */
+ /* queue prepare watchers (and execute them) */
if (expect_false (preparecnt))
{
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
{
ev_tstamp block;
- if (expect_false (flags & EVLOOP_NONBLOCK || idlecnt || !activecnt))
+ if (expect_false (flags & EVLOOP_NONBLOCK || idleall || !activecnt))
block = 0.; /* do not block at all */
else
{
/* update time to cancel out callback processing overhead */
-#if EV_USE_MONOTONIC
- if (expect_true (have_monotonic))
- time_update_monotonic (EV_A);
- else
-#endif
- {
- ev_rt_now = ev_time ();
- mn_now = ev_rt_now;
- }
+ time_update (EV_A_ 1e100);
block = MAX_BLOCKTIME;
++loop_count;
backend_poll (EV_A_ block);
- }
- /* update ev_rt_now, do magic */
- time_update (EV_A);
+ /* update ev_rt_now, do magic */
+ time_update (EV_A_ block);
+ }
/* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last */
periodics_reify (EV_A); /* absolute timers called first */
#endif
+#if EV_IDLE_ENABLE
/* queue idle watchers unless other events are pending */
- if (idlecnt && !any_pending (EV_A))
- queue_events (EV_A_ (W *)idles, idlecnt, EV_IDLE);
+ idle_reify (EV_A);
+#endif
/* queue check watchers, to be executed first */
if (expect_false (checkcnt))
}
void inline_speed
-ev_clear_pending (EV_P_ W w)
+clear_pending (EV_P_ W w)
{
if (w->pending)
{
}
}
+int
+ev_clear_pending (EV_P_ void *w)
+{
+ W w_ = (W)w;
+ int pending = w_->pending;
+
+ if (expect_true (pending))
+ {
+ ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1;
+ w_->pending = 0;
+ p->w = 0;
+ return p->events;
+ }
+ else
+ return 0;
+}
+
+void inline_size
+pri_adjust (EV_P_ W w)
+{
+ int pri = w->priority;
+ pri = pri < EV_MINPRI ? EV_MINPRI : pri;
+ pri = pri > EV_MAXPRI ? EV_MAXPRI : pri;
+ w->priority = pri;
+}
+
void inline_speed
ev_start (EV_P_ W w, int active)
{
- if (w->priority < EV_MINPRI) w->priority = EV_MINPRI;
- if (w->priority > EV_MAXPRI) w->priority = EV_MAXPRI;
-
+ pri_adjust (EV_A_ w);
w->active = active;
ev_ref (EV_A);
}
/*****************************************************************************/
-void
+void noinline
ev_io_start (EV_P_ ev_io *w)
{
int fd = w->fd;
fd_change (EV_A_ fd);
}
-void
+void noinline
ev_io_stop (EV_P_ ev_io *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
fd_change (EV_A_ w->fd);
}
-void
+void noinline
ev_timer_start (EV_P_ ev_timer *w)
{
if (expect_false (ev_is_active (w)))
/*assert (("internal timer heap corruption", timers [((W)w)->active - 1] == w));*/
}
-void
+void noinline
ev_timer_stop (EV_P_ ev_timer *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
ev_stop (EV_A_ (W)w);
}
-void
+void noinline
ev_timer_again (EV_P_ ev_timer *w)
{
if (ev_is_active (w))
}
#if EV_PERIODIC_ENABLE
-void
+void noinline
ev_periodic_start (EV_P_ ev_periodic *w)
{
if (expect_false (ev_is_active (w)))
{
assert (("ev_periodic_start called with negative interval value", w->interval >= 0.));
/* this formula differs from the one in periodic_reify because we do not always round up */
- ((WT)w)->at += ceil ((ev_rt_now - ((WT)w)->at) / w->interval) * w->interval;
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
}
+ else
+ ((WT)w)->at = w->offset;
ev_start (EV_A_ (W)w, ++periodiccnt);
array_needsize (ev_periodic *, periodics, periodicmax, periodiccnt, EMPTY2);
/*assert (("internal periodic heap corruption", periodics [((W)w)->active - 1] == w));*/
}
-void
+void noinline
ev_periodic_stop (EV_P_ ev_periodic *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
ev_stop (EV_A_ (W)w);
}
-void
+void noinline
ev_periodic_again (EV_P_ ev_periodic *w)
{
/* TODO: use adjustheap and recalculation */
# define SA_RESTART 0
#endif
-void
+void noinline
ev_signal_start (EV_P_ ev_signal *w)
{
#if EV_MULTIPLICITY
}
}
-void
+void noinline
ev_signal_stop (EV_P_ ev_signal *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_child_stop (EV_P_ ev_child *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_stat_stop (EV_P_ ev_stat *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
}
#endif
+#if EV_IDLE_ENABLE
void
ev_idle_start (EV_P_ ev_idle *w)
{
if (expect_false (ev_is_active (w)))
return;
- ev_start (EV_A_ (W)w, ++idlecnt);
- array_needsize (ev_idle *, idles, idlemax, idlecnt, EMPTY2);
- idles [idlecnt - 1] = w;
+ pri_adjust (EV_A_ (W)w);
+
+ {
+ int active = ++idlecnt [ABSPRI (w)];
+
+ ++idleall;
+ ev_start (EV_A_ (W)w, active);
+
+ array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2);
+ idles [ABSPRI (w)][active - 1] = w;
+ }
}
void
ev_idle_stop (EV_P_ ev_idle *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
{
int active = ((W)w)->active;
- idles [active - 1] = idles [--idlecnt];
- ((W)idles [active - 1])->active = active;
- }
- ev_stop (EV_A_ (W)w);
+ idles [ABSPRI (w)][active - 1] = idles [ABSPRI (w)][--idlecnt [ABSPRI (w)]];
+ ((W)idles [ABSPRI (w)][active - 1])->active = active;
+
+ ev_stop (EV_A_ (W)w);
+ --idleall;
+ }
}
+#endif
void
ev_prepare_start (EV_P_ ev_prepare *w)
void
ev_prepare_stop (EV_P_ ev_prepare *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_check_stop (EV_P_ ev_check *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_embed_stop (EV_P_ ev_embed *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_fork_stop (EV_P_ ev_fork *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;