Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
unix: fix event loop stall
Browse files Browse the repository at this point in the history
Undoes most of the changes made to libev in 7d2ea31 and c9396dd.
  • Loading branch information
bnoordhuis committed Jun 6, 2012
1 parent 6fe7530 commit 649ad50
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 35 deletions.
2 changes: 1 addition & 1 deletion include/uv-private/ev.h
Expand Up @@ -623,7 +623,7 @@ enum {
};

#if EV_PROTOTYPES
void ev_run (EV_P_ ev_tstamp waittime);
void ev_run (EV_P_ int flags EV_CPP (= 0));
void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)); /* break out of the loop */

/*
Expand Down
39 changes: 11 additions & 28 deletions src/unix/core.c
Expand Up @@ -226,16 +226,6 @@ void uv_loop_delete(uv_loop_t* loop) {
}


static void uv__poll(uv_loop_t* loop, unsigned int timeout) {
/* bump the loop's refcount, otherwise libev does
* a zero timeout poll and we end up busy looping
*/
ev_ref(loop->ev);
ev_run(loop->ev, timeout / 1000.);
ev_unref(loop->ev);
}


static unsigned int uv__poll_timeout(uv_loop_t* loop) {
if (!uv__has_active_handles(loop))
return 0;
Expand All @@ -247,22 +237,22 @@ static unsigned int uv__poll_timeout(uv_loop_t* loop) {
}


static void uv__poll(uv_loop_t* loop) {
void ev__run(EV_P_ ev_tstamp waittime);
ev_invoke_pending(loop->ev);
ev__run(loop->ev, uv__poll_timeout(loop) / 1000.);
ev_invoke_pending(loop->ev);
}


static int uv__run(uv_loop_t* loop) {
uv_update_time(loop);
uv__run_timers(loop);
uv__run_idle(loop);

if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) {
uv__run_prepare(loop);
/* Need to poll even if there are no active handles left, otherwise
* uv_work_t reqs won't complete...
*/
uv__poll(loop, uv__poll_timeout(loop));
uv__run_check(loop);
}

uv__run_prepare(loop);
uv__poll(loop);
uv__run_check(loop);
uv__run_closing_handles(loop);

return uv__has_active_handles(loop) || uv__has_active_reqs(loop);
}

Expand Down Expand Up @@ -604,13 +594,6 @@ static void uv__io_rw(struct ev_loop* ev, ev_io* w, int events) {
uv__io_t* handle = container_of(w, uv__io_t, io_watcher);
u.data = handle->io_watcher.data;
u.cb(loop, handle, events & (EV_READ|EV_WRITE|EV_ERROR));

/* The callback may have closed all active handles. Stop libev from entering
* the epoll_wait/kevent/port_getn/etc. syscall if that's the case, it would
* hang indefinitely.
*/
if (loop->active_handles == 0)
ev_break(loop->ev, EVBREAK_ONE);
}


Expand Down
103 changes: 97 additions & 6 deletions src/unix/ev/ev.c
Expand Up @@ -2389,7 +2389,7 @@ time_update (EV_P_ ev_tstamp max_block)
}

void
ev_run (EV_P_ ev_tstamp waittime)
ev_run (EV_P_ int flags)
{
#if EV_FEATURE_API
++loop_depth;
Expand Down Expand Up @@ -2426,6 +2426,15 @@ ev_run (EV_P_ ev_tstamp waittime)
}
#endif

#if EV_PREPARE_ENABLE
/* queue prepare watchers (and execute them) */
if (expect_false (preparecnt))
{
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
EV_INVOKE_PENDING;
}
#endif

if (expect_false (loop_done))
break;

Expand All @@ -2436,16 +2445,90 @@ ev_run (EV_P_ ev_tstamp waittime)
/* update fd-related kernel structures */
fd_reify (EV_A);

/* calculate blocking time */
{
ev_tstamp waittime = 0.;
ev_tstamp sleeptime = 0.;

/* remember old timestamp for io_blocktime calculation */
ev_tstamp prev_mn_now = mn_now;

/* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100);

if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
{
waittime = MAX_BLOCKTIME;

if (timercnt)
{
ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge;
if (waittime > to) waittime = to;
}

#if EV_PERIODIC_ENABLE
if (periodiccnt)
{
ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge;
if (waittime > to) waittime = to;
}
#endif

/* don't let timeouts decrease the waittime below timeout_blocktime */
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime;

/* extra check because io_blocktime is commonly 0 */
if (expect_false (io_blocktime))
{
sleeptime = io_blocktime - (mn_now - prev_mn_now);

if (sleeptime > waittime - backend_fudge)
sleeptime = waittime - backend_fudge;

if (expect_true (sleeptime > 0.))
{
ev_sleep (sleeptime);
waittime -= sleeptime;
}
}
}

#if EV_FEATURE_API
++loop_count;
++loop_count;
#endif
assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */

/* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
}

/* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last */
#if EV_PERIODIC_ENABLE
periodics_reify (EV_A); /* absolute timers called first */
#endif

#if EV_IDLE_ENABLE
/* queue idle watchers unless other events are pending */
idle_reify (EV_A);
#endif

#if EV_CHECK_ENABLE
/* queue check watchers, to be executed first */
if (expect_false (checkcnt))
queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
#endif
assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */

EV_INVOKE_PENDING;
}
while (0);
while (expect_true (
activecnt
&& !loop_done
&& !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
));

if (loop_done == EVBREAK_ONE)
loop_done = EVBREAK_CANCEL;
Expand All @@ -2455,6 +2538,14 @@ ev_run (EV_P_ ev_tstamp waittime)
#endif
}

/* libuv special */
void
ev__run (EV_P_ ev_tstamp waittime)
{
fd_reify (EV_A);
backend_poll (EV_A_ waittime);
}

void
ev_break (EV_P_ int how)
{
Expand Down

0 comments on commit 649ad50

Please sign in to comment.