aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2017-05-30 01:25:25 +0200
committerJustin M. Keyes <justinkz@gmail.com>2017-06-07 00:26:21 +0200
commit698ec9eb6e97ce9038e5f95a3208b7a0ac8da805 (patch)
tree0692e508d6a455adaa59b611fee8802b0033df7e /src
parentf83d733318d27ed8ad9fc7a442142ee8a74b7a39 (diff)
downloadrneovim-698ec9eb6e97ce9038e5f95a3208b7a0ac8da805.tar.gz
rneovim-698ec9eb6e97ce9038e5f95a3208b7a0ac8da805.tar.bz2
rneovim-698ec9eb6e97ce9038e5f95a3208b7a0ac8da805.zip
loop_close: Avoid infinite loop, and log it.
Avoids a hang, and also helps diagnose issues like: https://github.com/neovim/neovim/pull/6594#issuecomment-298321826
Diffstat (limited to 'src')
-rw-r--r--src/nvim/event/loop.c21
-rw-r--r--src/nvim/main.c7
-rw-r--r--src/nvim/os_unix.c4
3 files changed, 25 insertions, 7 deletions
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index c709ce9a1c..25701a1621 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -8,6 +8,7 @@
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
+#include "nvim/log.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/loop.c.generated.h"
@@ -78,20 +79,34 @@ void loop_on_put(MultiQueue *queue, void *data)
uv_stop(&loop->uv);
}
-void loop_close(Loop *loop, bool wait)
+/// @returns false if the loop could not be closed gracefully
+bool loop_close(Loop *loop, bool wait)
{
+ bool rv = true;
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, NULL);
uv_close((uv_handle_t *)&loop->async, NULL);
- do {
+ uint64_t start = wait ? os_hrtime() : 0;
+ while (true) {
uv_run(&loop->uv, wait ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
- } while (uv_loop_close(&loop->uv) && wait);
+ if (!uv_loop_close(&loop->uv) || !wait) {
+ break;
+ }
+ if (os_hrtime() - start >= 2 * 1000000000) {
+ // Some libuv resource was not correctly deref'd. Log and bail.
+ rv = false;
+ ELOG("uv_loop_close() hang?");
+ log_uv_handles(&loop->uv);
+ break;
+ }
+ }
multiqueue_free(loop->fast_events);
multiqueue_free(loop->thread_events);
multiqueue_free(loop->events);
kl_destroy(WatcherPtr, loop->children);
+ return rv;
}
void loop_purge(Loop *loop)
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 46607da6ea..19a661d7db 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -153,10 +153,11 @@ void event_init(void)
terminal_init();
}
-void event_teardown(void)
+/// @returns false if main_loop could not be closed gracefully
+bool event_teardown(void)
{
if (!main_loop.events) {
- return;
+ return true;
}
multiqueue_process_events(main_loop.events);
@@ -168,7 +169,7 @@ void event_teardown(void)
signal_teardown();
terminal_teardown();
- loop_close(&main_loop, true);
+ return loop_close(&main_loop, true);
}
/// Performs early initialization.
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index fb648fbcf8..692bcc97f4 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -141,7 +141,9 @@ void mch_exit(int r) FUNC_ATTR_NORETURN
ui_flush();
ml_close_all(true); // remove all memfiles
- event_teardown();
+ if (!event_teardown() && r == 0) {
+ r = 1; // Exit with error if main_loop did not teardown gracefully.
+ }
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
#ifdef EXITFREE