Skip to content

Commit

Permalink
loop_close: call uv_stop(), fix bug
Browse files Browse the repository at this point in the history
- Call uv_stop().
- Restore `uv_loop_close` condition (braindead cosmetic change from
  a2efc9c that caused uv_loop_close *not* to be called if
  wait=false, sorry).

Not doing `uv_walk(() => uv_close)`: see source comment for explanation.

fix neovim#11820
fix neovim#7376

Q: Should we restore use of `UV_RUN_DEFAULT`/`UV_RUN_ONCE` (removed in
   a2efc9c)?
A: The while-loop (hopefully) achieves the same purpose while avoiding
   a hang.
  • Loading branch information
justinmk committed Feb 19, 2020
1 parent 284b398 commit d273036
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions src/nvim/event/loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,35 @@ void loop_on_put(MultiQueue *queue, void *data)
uv_stop(&loop->uv);
}

/// 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)
{
bool rv = true;
// Loop won’t 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_close((uv_handle_t *)&loop->children_watcher, 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->async, NULL);
uint64_t start = wait ? os_hrtime() : 0;
while (true) {
// 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, UV_RUN_NOWAIT);
if (!wait || (uv_loop_close(&loop->uv) != UV_EBUSY)) {
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?");
Expand Down

0 comments on commit d273036

Please sign in to comment.