diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2020-02-18 20:34:07 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-18 20:34:07 -0800 |
commit | ce15977d708886a3d55fa21127abc7145dc7aaf8 (patch) | |
tree | 433686fdf9ec9041a6063ac69536cc56efffe538 | |
parent | a2efc9cf8b0fdf14b01156ba424145e1847f789c (diff) | |
parent | ceac76daa53fc6f12eab40c2804914dfd503c279 (diff) | |
download | rneovim-ce15977d708886a3d55fa21127abc7145dc7aaf8.tar.gz rneovim-ce15977d708886a3d55fa21127abc7145dc7aaf8.tar.bz2 rneovim-ce15977d708886a3d55fa21127abc7145dc7aaf8.zip |
Merge #11887 'loop_close: close all handles'
-rw-r--r-- | src/nvim/event/loop.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index 664f3ad89d..e341513ae1 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -116,6 +116,20 @@ void loop_on_put(MultiQueue *queue, void *data) 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. +/// +/// @param loop Loop to destroy +/// @param wait Wait briefly for handles to deref +/// /// @returns false if the loop could not be closed gracefully bool loop_close(Loop *loop, bool wait) { @@ -126,18 +140,34 @@ bool loop_close(Loop *loop, bool wait) uv_close((uv_handle_t *)&loop->poll_timer, timer_close_cb); uv_close((uv_handle_t *)&loop->async, NULL); uint64_t start = wait ? os_hrtime() : 0; + bool didstop = false; while (true) { - uv_run(&loop->uv, UV_RUN_NOWAIT); - if (!wait || (uv_loop_close(&loop->uv) != UV_EBUSY)) { + // Run the loop to tickle close-callbacks (which should then free memory). + // Use UV_RUN_NOWAIT to avoid a hang. #11820 + uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); + if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) { break; } - if (os_hrtime() - start >= 2 * 1000000000) { + uint64_t elapsed_s = (os_hrtime() - start) / 1000000000; // seconds + if (elapsed_s >= 2) { // Some libuv resource was not correctly deref'd. Log and bail. rv = false; ELOG("uv_loop_close() hang?"); log_uv_handles(&loop->uv); break; } +#if defined(EXITFREE) + (void)didstop; +#else + if (!didstop) { + // Loop won’t 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->thread_events); |