loop_close: close all handles

- Move uv_stop(), it still causes a "leak" on exit somehow.
- Tenatively restore `UV_RUN_DEFAULT`.  It shouldn't hang since we
  clobber the handles via `uv_walk((h)=>uv_close(h))`. Although this
  still "leaks" on exit, it's faster than the 2-second timeout.

fix #11820
fix #7376
This commit is contained in:
Justin M. Keyes 2020-02-17 23:50:59 -08:00
parent d2730365ef
commit 47bd62c15c

View File

@ -116,6 +116,15 @@ void loop_on_put(MultiQueue *queue, void *data)
uv_stop(&loop->uv); uv_stop(&loop->uv);
} }
#if !defined(EXITFREE)
static void loop_walk_cb(uv_handle_t *handle, void *arg)
{
if (!uv_is_closing(handle)) {
uv_close(handle, NULL);
}
}
#endif
/// Closes `loop` and its handles, and frees its structures. /// Closes `loop` and its handles, and frees its structures.
/// ///
/// @param loop Loop to destroy /// @param loop Loop to destroy
@ -125,21 +134,17 @@ void loop_on_put(MultiQueue *queue, void *data)
bool loop_close(Loop *loop, bool wait) bool loop_close(Loop *loop, bool wait)
{ {
bool rv = true; bool rv = true;
// Loop wont block for I/O after this.
uv_stop(&loop->uv);
// TODO(justinmk): Close all (lua/luv!) handles. But walk_cb() needs to call
// the resource-specific close-callbacks...
// uv_walk((h) => { if !uv_is_closing(h) { uv_close(h, …) } })
uv_mutex_destroy(&loop->mutex); uv_mutex_destroy(&loop->mutex);
uv_close((uv_handle_t *)&loop->children_watcher, NULL); uv_close((uv_handle_t *)&loop->children_watcher, NULL);
uv_close((uv_handle_t *)&loop->children_kill_timer, NULL); uv_close((uv_handle_t *)&loop->children_kill_timer, NULL);
uv_close((uv_handle_t *)&loop->poll_timer, timer_close_cb); uv_close((uv_handle_t *)&loop->poll_timer, timer_close_cb);
uv_close((uv_handle_t *)&loop->async, NULL); uv_close((uv_handle_t *)&loop->async, NULL);
uint64_t start = wait ? os_hrtime() : 0; uint64_t start = wait ? os_hrtime() : 0;
bool didstop = false;
while (true) { while (true) {
// Run the loop to tickle close-callbacks (which should then free memory). // Run the loop to tickle close-callbacks (which should then free memory).
// Use UV_RUN_NOWAIT to avoid a hang. #11820 // Use UV_RUN_NOWAIT to avoid a hang. #11820
uv_run(&loop->uv, UV_RUN_NOWAIT); uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) { if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) {
break; break;
} }
@ -151,6 +156,18 @@ bool loop_close(Loop *loop, bool wait)
log_uv_handles(&loop->uv); log_uv_handles(&loop->uv);
break; break;
} }
#if defined(EXITFREE)
(void)didstop;
#else
if (!didstop) {
// Loop wont block for I/O after this.
uv_stop(&loop->uv);
// XXX: Close all (lua/luv!) handles. But loop_walk_cb() does not call
// resource-specific close-callbacks, so this leaks memory...
uv_walk(&loop->uv, loop_walk_cb, NULL);
didstop = true;
}
#endif
} }
multiqueue_free(loop->fast_events); multiqueue_free(loop->fast_events);
multiqueue_free(loop->thread_events); multiqueue_free(loop->thread_events);