X-Git-Url: https://git.llucax.com/software/libev.git/blobdiff_plain/4b05fe94e44407cd62092863e204337c521e7d8a..c4977e2742acfd90d4c4abd068f1c9e284951ef5:/ev.c?ds=sidebyside diff --git a/ev.c b/ev.c index e3e7e57..dedd4f3 100644 --- a/ev.c +++ b/ev.c @@ -128,7 +128,11 @@ #define PID_HASHSIZE 16 /* size of pid hash table, must be power of two */ /*#define CLEANUP_INTERVAL 300. /* how often to try to free memory and re-check fds */ -#include "ev.h" +#ifdef EV_H +# include EV_H +#else +# include "ev.h" +#endif #if __GNUC__ >= 3 # define expect(expr,value) __builtin_expect ((expr),(value)) @@ -217,19 +221,24 @@ typedef struct #if EV_MULTIPLICITY -struct ev_loop -{ -# define VAR(name,decl) decl; -# include "ev_vars.h" -}; -# undef VAR -# include "ev_wrap.h" + struct ev_loop + { + #define VAR(name,decl) decl; + #include "ev_vars.h" + #undef VAR + }; + #include "ev_wrap.h" + + struct ev_loop default_loop_struct; + static struct ev_loop *default_loop; #else -# define VAR(name,decl) static decl; -# include "ev_vars.h" -# undef VAR + #define VAR(name,decl) static decl; + #include "ev_vars.h" + #undef VAR + + static int default_loop; #endif @@ -318,19 +327,21 @@ anfds_init (ANFD *base, int count) } } -static void -event (EV_P_ W w, int events) +void +ev_feed_event (EV_P_ void *w, int revents) { - if (w->pending) + W w_ = (W)w; + + if (w_->pending) { - pendings [ABSPRI (w)][w->pending - 1].events |= events; + pendings [ABSPRI (w_)][w_->pending - 1].events |= revents; return; } - w->pending = ++pendingcnt [ABSPRI (w)]; - array_needsize (ANPENDING, pendings [ABSPRI (w)], pendingmax [ABSPRI (w)], pendingcnt [ABSPRI (w)], (void)); - pendings [ABSPRI (w)][w->pending - 1].w = w; - pendings [ABSPRI (w)][w->pending - 1].events = events; + w_->pending = ++pendingcnt [ABSPRI (w_)]; + array_needsize (ANPENDING, pendings [ABSPRI (w_)], pendingmax [ABSPRI (w_)], pendingcnt [ABSPRI (w_)], (void)); + pendings [ABSPRI (w_)][w_->pending - 1].w = w_; + pendings [ABSPRI (w_)][w_->pending - 1].events = revents; } static void @@ -339,24 +350,30 @@ queue_events (EV_P_ W *events, int eventcnt, int type) int i; for (i = 0; i < eventcnt; ++i) - event (EV_A_ events [i], type); + ev_feed_event (EV_A_ events [i], type); } -static void -fd_event (EV_P_ int fd, int events) +inline void +fd_event (EV_P_ int fd, int revents) { ANFD *anfd = anfds + fd; struct ev_io *w; for (w = (struct ev_io *)anfd->head; w; w = (struct ev_io *)((WL)w)->next) { - int ev = w->events & events; + int ev = w->events & revents; if (ev) - event (EV_A_ (W)w, ev); + ev_feed_event (EV_A_ (W)w, ev); } } +void +ev_feed_fd_event (EV_P_ int fd, int revents) +{ + fd_event (EV_A_ fd, revents); +} + /*****************************************************************************/ static void @@ -405,7 +422,7 @@ fd_kill (EV_P_ int fd) while ((w = (struct ev_io *)anfds [fd].head)) { ev_io_stop (EV_A_ w); - event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE); + ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE); } } @@ -543,28 +560,50 @@ sighandler (int signum) { int old_errno = errno; gotsig = 1; +#ifdef WIN32 + send (sigpipe [1], &signum, 1, MSG_DONTWAIT); +#else write (sigpipe [1], &signum, 1); +#endif errno = old_errno; } } +void +ev_feed_signal_event (EV_P_ int signum) +{ + WL w; + +#if EV_MULTIPLICITY + assert (("feeding signal events is only supported in the default loop", loop == default_loop)); +#endif + + --signum; + + if (signum < 0 || signum >= signalmax) + return; + + signals [signum].gotsig = 0; + + for (w = signals [signum].head; w; w = w->next) + ev_feed_event (EV_A_ (W)w, EV_SIGNAL); +} + static void sigcb (EV_P_ struct ev_io *iow, int revents) { - WL w; int signum; +#ifdef WIN32 + recv (sigpipe [0], &revents, 1, MSG_DONTWAIT); +#else read (sigpipe [0], &revents, 1); +#endif gotsig = 0; for (signum = signalmax; signum--; ) if (signals [signum].gotsig) - { - signals [signum].gotsig = 0; - - for (w = signals [signum].head; w; w = w->next) - event (EV_A_ (W)w, EV_SIGNAL); - } + ev_feed_signal_event (EV_A_ signum + 1); } static void @@ -607,7 +646,7 @@ child_reap (EV_P_ struct ev_signal *sw, int chain, int pid, int status) ev_priority (w) = ev_priority (sw); /* need to do it *now* */ w->rpid = pid; w->rstatus = status; - event (EV_A_ (W)w, EV_CHILD); + ev_feed_event (EV_A_ (W)w, EV_CHILD); } } @@ -619,7 +658,7 @@ childcb (EV_P_ struct ev_signal *sw, int revents) if (0 < (pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED))) { /* make sure we are called again until all childs have been reaped */ - event (EV_A_ (W)sw, EV_SIGNAL); + ev_feed_event (EV_A_ (W)sw, EV_SIGNAL); child_reap (EV_A_ sw, pid, pid, status); child_reap (EV_A_ sw, 0, pid, status); /* this might trigger a watcher twice, but event catches that */ @@ -814,13 +853,8 @@ ev_loop_fork (EV_P) #endif #if EV_MULTIPLICITY -struct ev_loop default_loop_struct; -static struct ev_loop *default_loop; - struct ev_loop * #else -static int default_loop; - int #endif ev_default_loop (int methods) @@ -891,6 +925,18 @@ ev_default_fork (void) /*****************************************************************************/ +static int +any_pending (EV_P) +{ + int pri; + + for (pri = NUMPRI; pri--; ) + if (pendingcnt [pri]) + return 1; + + return 0; +} + static void call_pending (EV_P) { @@ -904,7 +950,7 @@ call_pending (EV_P) if (p->w) { p->w->pending = 0; - p->w->cb (EV_A_ p->w, p->events); + EV_CB_INVOKE (p->w, p->events); } } } @@ -928,7 +974,7 @@ timers_reify (EV_P) else ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer */ - event (EV_A_ (W)w, EV_TIMEOUT); + ev_feed_event (EV_A_ (W)w, EV_TIMEOUT); } } @@ -942,7 +988,14 @@ periodics_reify (EV_P) assert (("inactive timer on periodic heap detected", ev_is_active (w))); /* first reschedule or stop timer */ - if (w->interval) + if (w->reschedule_cb) + { + ev_tstamp at = ((WT)w)->at = w->reschedule_cb (w, rt_now + 0.0001); + + assert (("ev_periodic reschedule callback returned time in the past", ((WT)w)->at > rt_now)); + downheap ((WT *)periodics, periodiccnt, 0); + } + else if (w->interval) { ((WT)w)->at += floor ((rt_now - ((WT)w)->at) / w->interval + 1.) * w->interval; assert (("ev_periodic timeout in the past detected while processing timers, negative interval?", ((WT)w)->at > rt_now)); @@ -951,7 +1004,7 @@ periodics_reify (EV_P) else ev_periodic_stop (EV_A_ w); /* nonrepeating: stop timer */ - event (EV_A_ (W)w, EV_PERIODIC); + ev_feed_event (EV_A_ (W)w, EV_PERIODIC); } } @@ -965,19 +1018,15 @@ periodics_reschedule (EV_P) { struct ev_periodic *w = periodics [i]; - if (w->interval) - { - ev_tstamp diff = ceil ((rt_now - ((WT)w)->at) / w->interval) * w->interval; - - if (fabs (diff) >= 1e-4) - { - ev_periodic_stop (EV_A_ w); - ev_periodic_start (EV_A_ w); - - i = 0; /* restart loop, inefficient, but time jumps should be rare */ - } - } + if (w->reschedule_cb) + ((WT)w)->at = w->reschedule_cb (w, rt_now); + else if (w->interval) + ((WT)w)->at += ceil ((rt_now - ((WT)w)->at) / w->interval) * w->interval; } + + /* now rebuild the heap */ + for (i = periodiccnt >> 1; i--; ) + downheap ((WT *)periodics, periodiccnt, i); } inline int @@ -1083,7 +1132,7 @@ ev_loop (EV_P_ int flags) /* calculate blocking time */ - /* we only need this for !monotonic clockor timers, but as we basically + /* we only need this for !monotonic clock or timers, but as we basically always have timers, we just calculate it always */ #if EV_USE_MONOTONIC if (expect_true (have_monotonic)) @@ -1126,7 +1175,7 @@ ev_loop (EV_P_ int flags) periodics_reify (EV_A); /* absolute timers called first */ /* queue idle watchers unless io or timers are pending */ - if (!pendingcnt) + if (idlecnt && !any_pending (EV_A)) queue_events (EV_A_ (W *)idles, idlecnt, EV_IDLE); /* queue check watchers, to be executed first */ @@ -1291,11 +1340,14 @@ ev_periodic_start (EV_P_ struct ev_periodic *w) if (ev_is_active (w)) return; - 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 */ - if (w->interval) - ((WT)w)->at += ceil ((rt_now - ((WT)w)->at) / w->interval) * w->interval; + if (w->reschedule_cb) + ((WT)w)->at = w->reschedule_cb (w, rt_now); + else if (w->interval) + { + 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 ((rt_now - ((WT)w)->at) / w->interval) * w->interval; + } ev_start (EV_A_ (W)w, ++periodiccnt); array_needsize (struct ev_periodic *, periodics, periodicmax, periodiccnt, (void)); @@ -1323,6 +1375,13 @@ ev_periodic_stop (EV_P_ struct ev_periodic *w) ev_stop (EV_A_ (W)w); } +void +ev_periodic_again (EV_P_ struct ev_periodic *w) +{ + ev_periodic_stop (EV_A_ w); + ev_periodic_start (EV_A_ w); +} + void ev_idle_start (EV_P_ struct ev_idle *w) {