diff options
38 files changed, 499 insertions, 338 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index ad5bac1898..4448859b64 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -30,15 +30,17 @@ file(MAKE_DIRECTORY ${GENERATED_DIR}/api) file(MAKE_DIRECTORY ${GENERATED_DIR}/api/private) file(MAKE_DIRECTORY ${GENERATED_DIR}/msgpack_rpc) file(MAKE_DIRECTORY ${GENERATED_DIR}/tui) +file(MAKE_DIRECTORY ${GENERATED_DIR}/event) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/os) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api/private) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/msgpack_rpc) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/tui) +file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/event) file(GLOB NEOVIM_SOURCES *.c os/*.c api/*.c api/private/*.c msgpack_rpc/*.c - tui/*.c) + tui/*.c event/*.c) file(GLOB_RECURSE NEOVIM_HEADERS *.h) file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index dd82b06158..390d62210b 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -59,7 +59,7 @@ #include "nvim/terminal.h" #include "nvim/undo.h" #include "nvim/window.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/input.h" #include "nvim/os/time.h" @@ -601,15 +601,15 @@ edit ( * Get a character for Insert mode. Ignore K_IGNORE. */ lastc = c; /* remember previous char for CTRL-D */ - event_enable_deferred(); + loop_enable_deferred_events(&loop); do { c = safe_vgetc(); } while (c == K_IGNORE); - event_disable_deferred(); + loop_disable_deferred_events(&loop); if (c == K_EVENT) { c = lastc; - event_process(); + loop_process_event(&loop); continue; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7da5cfb731..4173acefd9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -91,8 +91,8 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/os/dl.h" -#include "nvim/os/event.h" #include "nvim/os/input.h" +#include "nvim/event/loop.h" #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ @@ -10966,7 +10966,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) if (!disable_job_defer++) { // process any pending job events in the deferred queue, but only do this if // deferred is not disabled(at the top-level `jobwait()` call) - event_process(); + loop_process_event(&loop); } // For each item in the input list append an integer to the output list. -3 // is used to represent an invalid job id, -2 is for a interrupted job and @@ -11026,7 +11026,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) } // poll to ensure any pending callbacks from the last job are invoked - event_poll(0); + loop_poll_events(&loop, 0); for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) { Job *job = NULL; @@ -20347,7 +20347,7 @@ static inline void push_job_event(Job *job, ufunc_T *callback, event_data->data = job_data(job); event_data->callback = callback; event_data->type = type; - event_push((Event) { + loop_push_event(&loop, (Event) { .handler = on_job_event, .data = event_data }, !disable_job_defer); diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c new file mode 100644 index 0000000000..c467ae8b96 --- /dev/null +++ b/src/nvim/event/loop.c @@ -0,0 +1,137 @@ +#include <stdint.h> + +#include <uv.h> + +#include "nvim/event/loop.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "event/loop.c.generated.h" +#endif + + +void loop_init(Loop *loop, void *data) +{ + uv_loop_init(&loop->uv); + loop->uv.data = loop; + loop->deferred_events = kl_init(Event); + loop->immediate_events = kl_init(Event); +} + +void loop_poll_events(Loop *loop, int ms) +{ + static int recursive = 0; + + if (recursive++) { + abort(); // Should not re-enter uv_run + } + + bool wait = true; + uv_timer_t timer; + + if (ms > 0) { + uv_timer_init(&loop->uv, &timer); + // Use a repeating timeout of ms milliseconds to make sure + // we do not block indefinitely for I/O. + uv_timer_start(&timer, timer_cb, (uint64_t)ms, (uint64_t)ms); + } else if (ms == 0) { + // For ms == 0, we need to do a non-blocking event poll by + // setting the run mode to UV_RUN_NOWAIT. + wait = false; + } + + if (wait) { + loop_run_once(loop); + } else { + loop_run_nowait(loop); + } + + if (ms > 0) { + // Ensure the timer handle is closed and run the event loop + // once more to let libuv perform it's cleanup + uv_timer_stop(&timer); + uv_close((uv_handle_t *)&timer, NULL); + loop_run_nowait(loop); + } + + recursive--; // Can re-enter uv_run now + process_events_from(loop->immediate_events); +} + +bool loop_has_deferred_events(Loop *loop) +{ + return loop->deferred_events_allowed && !kl_empty(loop->deferred_events); +} + +void loop_enable_deferred_events(Loop *loop) +{ + ++loop->deferred_events_allowed; +} + +void loop_disable_deferred_events(Loop *loop) +{ + --loop->deferred_events_allowed; +} + +// Queue an event +void loop_push_event(Loop *loop, Event event, bool deferred) +{ + // Sometimes libuv will run pending callbacks(timer for example) before + // blocking for a poll. If this happens and the callback pushes a event to one + // of the queues, the event would only be processed after the poll + // returns(user hits a key for example). To avoid this scenario, we call + // uv_stop when a event is enqueued. + loop_stop(loop); + kl_push(Event, deferred ? loop->deferred_events : loop->immediate_events, + event); +} + +void loop_process_event(Loop *loop) +{ + process_events_from(loop->deferred_events); +} + + +void loop_run(Loop *loop) +{ + uv_run(&loop->uv, UV_RUN_DEFAULT); +} + +void loop_run_once(Loop *loop) +{ + uv_run(&loop->uv, UV_RUN_ONCE); +} + +void loop_run_nowait(Loop *loop) +{ + uv_run(&loop->uv, UV_RUN_NOWAIT); +} + +void loop_stop(Loop *loop) +{ + uv_stop(&loop->uv); +} + +void loop_close(Loop *loop) +{ + do { + uv_run(&loop->uv, UV_RUN_DEFAULT); + } while (uv_loop_close(&loop->uv)); +} + +void loop_process_all_events(Loop *loop) +{ + process_events_from(loop->immediate_events); + process_events_from(loop->deferred_events); +} + +static void process_events_from(klist_t(Event) *queue) +{ + while (!kl_empty(queue)) { + Event event = kl_shift(Event, queue); + event.handler(event); + } +} + +static void timer_cb(uv_timer_t *handle) +{ +} diff --git a/src/nvim/os/event.h b/src/nvim/event/loop.h index db02b38c7f..e5a890dddb 100644 --- a/src/nvim/os/event.h +++ b/src/nvim/event/loop.h @@ -1,20 +1,40 @@ -#ifndef NVIM_OS_EVENT_H -#define NVIM_OS_EVENT_H +#ifndef NVIM_EVENT_LOOP_H +#define NVIM_EVENT_LOOP_H #include <stdint.h> -#include <stdbool.h> -#include "nvim/os/event_defs.h" -#include "nvim/os/job_defs.h" +#include <uv.h> + +#include "nvim/lib/klist.h" #include "nvim/os/time.h" +typedef struct event Event; +typedef void (*event_handler)(Event event); + +struct event { + void *data; + event_handler handler; +}; + +typedef void * WatcherPtr; + +#define _noop(x) +KLIST_INIT(WatcherPtr, WatcherPtr, _noop) +KLIST_INIT(Event, Event, _noop) + +typedef struct loop { + uv_loop_t uv; + klist_t(Event) *deferred_events, *immediate_events; + int deferred_events_allowed; +} Loop; + // Poll for events until a condition or timeout -#define event_poll_until(timeout, condition) \ +#define LOOP_POLL_EVENTS_UNTIL(loop, timeout, condition) \ do { \ int remaining = timeout; \ uint64_t before = (remaining > 0) ? os_hrtime() : 0; \ while (!(condition)) { \ - event_poll(remaining); \ + loop_poll_events(loop, remaining); \ if (remaining == 0) { \ break; \ } else if (remaining > 0) { \ @@ -29,7 +49,7 @@ } while (0) #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/event.h.generated.h" +# include "event/loop.h.generated.h" #endif -#endif // NVIM_OS_EVENT_H +#endif // NVIM_EVENT_LOOP_H diff --git a/src/nvim/event/signal.c b/src/nvim/event/signal.c new file mode 100644 index 0000000000..63133b4f57 --- /dev/null +++ b/src/nvim/event/signal.c @@ -0,0 +1,52 @@ +#include <uv.h> + +#include "nvim/event/loop.h" +#include "nvim/event/signal.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "event/signal.c.generated.h" +#endif + + +void signal_watcher_init(Loop *loop, SignalWatcher *watcher, void *data) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) +{ + uv_signal_init(&loop->uv, &watcher->uv); + watcher->uv.data = watcher; + watcher->data = data; + watcher->cb = NULL; +} + +void signal_watcher_start(SignalWatcher *watcher, signal_cb cb, int signum) + FUNC_ATTR_NONNULL_ALL +{ + watcher->cb = cb; + uv_signal_start(&watcher->uv, signal_watcher_cb, signum); +} + +void signal_watcher_stop(SignalWatcher *watcher) + FUNC_ATTR_NONNULL_ALL +{ + uv_signal_stop(&watcher->uv); +} + +void signal_watcher_close(SignalWatcher *watcher, signal_close_cb cb) + FUNC_ATTR_NONNULL_ARG(1) +{ + watcher->close_cb = cb; + uv_close((uv_handle_t *)&watcher->uv, close_cb); +} + +static void signal_watcher_cb(uv_signal_t *handle, int signum) +{ + SignalWatcher *watcher = handle->data; + watcher->cb(watcher, signum, watcher->data); +} + +static void close_cb(uv_handle_t *handle) +{ + SignalWatcher *watcher = handle->data; + if (watcher->close_cb) { + watcher->close_cb(watcher, watcher->data); + } +} diff --git a/src/nvim/event/signal.h b/src/nvim/event/signal.h new file mode 100644 index 0000000000..c269fa9d95 --- /dev/null +++ b/src/nvim/event/signal.h @@ -0,0 +1,22 @@ +#ifndef NVIM_EVENT_SIGNAL_H +#define NVIM_EVENT_SIGNAL_H + +#include <uv.h> + +#include "nvim/event/loop.h" + +typedef struct signal_watcher SignalWatcher; +typedef void (*signal_cb)(SignalWatcher *watcher, int signum, void *data); +typedef void (*signal_close_cb)(SignalWatcher *watcher, void *data); + +struct signal_watcher { + uv_signal_t uv; + void *data; + signal_cb cb; + signal_close_cb close_cb; +}; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "event/signal.h.generated.h" +#endif +#endif // NVIM_EVENT_SIGNAL_H diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c new file mode 100644 index 0000000000..ce33cdfc10 --- /dev/null +++ b/src/nvim/event/time.c @@ -0,0 +1,55 @@ +#include <stdint.h> + +#include <uv.h> + +#include "nvim/event/loop.h" +#include "nvim/event/time.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "event/time.c.generated.h" +#endif + + +void time_watcher_init(Loop *loop, TimeWatcher *watcher, void *data) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) +{ + uv_timer_init(&loop->uv, &watcher->uv); + watcher->uv.data = watcher; + watcher->data = data; +} + +void time_watcher_start(TimeWatcher *watcher, time_cb cb, uint64_t timeout, + uint64_t repeat) + FUNC_ATTR_NONNULL_ALL +{ + watcher->cb = cb; + uv_timer_start(&watcher->uv, time_watcher_cb, timeout, repeat); +} + +void time_watcher_stop(TimeWatcher *watcher) + FUNC_ATTR_NONNULL_ALL +{ + uv_timer_stop(&watcher->uv); +} + +void time_watcher_close(TimeWatcher *watcher, time_cb cb) + FUNC_ATTR_NONNULL_ARG(1) +{ + watcher->close_cb = cb; + uv_close((uv_handle_t *)&watcher->uv, close_cb); +} + +static void time_watcher_cb(uv_timer_t *handle) + FUNC_ATTR_NONNULL_ALL +{ + TimeWatcher *watcher = handle->data; + watcher->cb(watcher, watcher->data); +} + +static void close_cb(uv_handle_t *handle) +{ + TimeWatcher *watcher = handle->data; + if (watcher->close_cb) { + watcher->close_cb(watcher, watcher->data); + } +} diff --git a/src/nvim/event/time.h b/src/nvim/event/time.h new file mode 100644 index 0000000000..ee50e53d11 --- /dev/null +++ b/src/nvim/event/time.h @@ -0,0 +1,20 @@ +#ifndef NVIM_EVENT_TIME_H +#define NVIM_EVENT_TIME_H + +#include <uv.h> + +#include "nvim/event/loop.h" + +typedef struct time_watcher TimeWatcher; +typedef void (*time_cb)(TimeWatcher *watcher, void *data); + +struct time_watcher { + uv_timer_t uv; + void *data; + time_cb cb, close_cb; +}; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "event/time.h.generated.h" +#endif +#endif // NVIM_EVENT_TIME_H diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 3af035a6e3..785db1dbd1 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -63,7 +63,7 @@ #include "nvim/window.h" #include "nvim/ui.h" #include "nvim/os/os.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" /* * Variables shared between getcmdline(), redrawcmdline() and others. @@ -298,14 +298,14 @@ getcmdline ( /* Get a character. Ignore K_IGNORE, it should not do anything, such * as stop completion. */ - event_enable_deferred(); + loop_enable_deferred_events(&loop); do { c = safe_vgetc(); } while (c == K_IGNORE); - event_disable_deferred(); + loop_disable_deferred_events(&loop); if (c == K_EVENT) { - event_process(); + loop_process_event(&loop); continue; } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 864aa6a622..bbeef376b0 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -49,7 +49,7 @@ #include "nvim/strings.h" #include "nvim/ui.h" #include "nvim/undo.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/input.h" #include "nvim/os/os.h" diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 1d93900a94..c7164ef1f1 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -28,6 +28,7 @@ #include "nvim/menu.h" #include "nvim/syntax_defs.h" #include "nvim/types.h" +#include "nvim/event/loop.h" /* * definition of global variables @@ -1216,6 +1217,7 @@ EXTERN char *ignoredp; // If a msgpack-rpc channel should be started over stdin/stdout EXTERN bool embedded_mode INIT(= false); +EXTERN Loop loop; /// Used to track the status of external functions. /// Currently only used for iconv(). diff --git a/src/nvim/main.c b/src/nvim/main.c index 50c16c51d6..ca55469730 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -61,9 +61,13 @@ #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/time.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/signal.h" +#include "nvim/os/job.h" +#include "nvim/msgpack_rpc/defs.h" #include "nvim/msgpack_rpc/helpers.h" +#include "nvim/msgpack_rpc/server.h" +#include "nvim/msgpack_rpc/channel.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/handle.h" @@ -133,6 +137,42 @@ static const char *err_extra_cmd = N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"); +void event_init(void) +{ + loop_init(&loop, NULL); + // early msgpack-rpc initialization + msgpack_rpc_init_method_table(); + msgpack_rpc_helpers_init(); + // Initialize input events + input_init(); + // Timer to wake the event loop if a timeout argument is passed to + // `event_poll` + // Signals + signal_init(); + job_init(); + // finish mspgack-rpc initialization + channel_init(); + server_init(); + terminal_init(); +} + +void event_teardown(void) +{ + if (!loop.deferred_events) { + return; + } + + loop_process_all_events(&loop); + input_stop(); + channel_teardown(); + job_teardown(); + server_teardown(); + signal_teardown(); + terminal_teardown(); + + loop_close(&loop); +} + /// Performs early initialization. /// /// Needed for unit tests. Must be called after `time_init()`. diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 2a81b4f160..3932fa1f36 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -9,7 +9,7 @@ #include "nvim/api/vim.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/remote_ui.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/rstream.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/wstream.h" @@ -220,7 +220,7 @@ Object channel_send_call(uint64_t id, ChannelCallFrame frame = {request_id, false, false, NIL}; kv_push(ChannelCallFrame *, channel->call_stack, &frame); channel->pending_requests++; - event_poll_until(-1, frame.returned); + LOOP_POLL_EVENTS_UNTIL(&loop, -1, frame.returned); (void)kv_pop(channel->call_stack); channel->pending_requests--; @@ -474,7 +474,7 @@ static void handle_request(Channel *channel, msgpack_object *request) event_data->args = args; event_data->request_id = request_id; incref(channel); - event_push((Event) { + loop_push_event(&loop, (Event) { .handler = on_request_event, .data = event_data }, defer); @@ -648,7 +648,8 @@ static void close_channel(Channel *channel) if (handle) { uv_close(handle, close_cb); } else { - event_push((Event) { .handler = on_stdio_close, .data = channel }, false); + loop_push_event(&loop, + (Event) { .handler = on_stdio_close, .data = channel }, false); } } diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 388b5a04cf..1a78b3498f 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -180,14 +180,14 @@ int server_start(const char *endpoint) if (server_type == kServerTypeTcp) { // Listen on tcp address/port - uv_tcp_init(uv_default_loop(), &server->socket.tcp.handle); + uv_tcp_init(&loop.uv, &server->socket.tcp.handle); result = uv_tcp_bind(&server->socket.tcp.handle, (const struct sockaddr *)&server->socket.tcp.addr, 0); stream = (uv_stream_t *)&server->socket.tcp.handle; } else { // Listen on named pipe or unix socket - uv_pipe_init(uv_default_loop(), &server->socket.pipe.handle, 0); + uv_pipe_init(&loop.uv, &server->socket.pipe.handle, 0); result = uv_pipe_bind(&server->socket.pipe.handle, server->addr); stream = (uv_stream_t *)&server->socket.pipe.handle; } @@ -308,10 +308,10 @@ static void connection_cb(uv_stream_t *server, int status) if (srv->type == kServerTypeTcp) { client = xmalloc(sizeof(uv_tcp_t)); - uv_tcp_init(uv_default_loop(), (uv_tcp_t *)client); + uv_tcp_init(&loop.uv, (uv_tcp_t *)client); } else { client = xmalloc(sizeof(uv_pipe_t)); - uv_pipe_init(uv_default_loop(), (uv_pipe_t *)client, 0); + uv_pipe_init(&loop.uv, (uv_pipe_t *)client, 0); } result = uv_accept(server, client); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 92734e404a..b66bc31b74 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -61,7 +61,7 @@ #include "nvim/mouse.h" #include "nvim/undo.h" #include "nvim/window.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/time.h" /* @@ -487,12 +487,12 @@ normal_cmd ( /* * Get the command character from the user. */ - event_enable_deferred(); + loop_enable_deferred_events(&loop); c = safe_vgetc(); - event_disable_deferred(); + loop_disable_deferred_events(&loop); if (c == K_EVENT) { - event_process(); + loop_process_event(&loop); return; } diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c deleted file mode 100644 index 56874b495d..0000000000 --- a/src/nvim/os/event.c +++ /dev/null @@ -1,177 +0,0 @@ -#include <assert.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> - -#include <uv.h> - -#include "nvim/os/event.h" -#include "nvim/os/input.h" -#include "nvim/msgpack_rpc/defs.h" -#include "nvim/msgpack_rpc/channel.h" -#include "nvim/msgpack_rpc/server.h" -#include "nvim/msgpack_rpc/helpers.h" -#include "nvim/os/signal.h" -#include "nvim/os/rstream.h" -#include "nvim/os/wstream.h" -#include "nvim/os/job.h" -#include "nvim/vim.h" -#include "nvim/memory.h" -#include "nvim/misc2.h" -#include "nvim/ui.h" -#include "nvim/screen.h" -#include "nvim/terminal.h" - -#include "nvim/lib/klist.h" - -// event will be cleaned up after it gets processed -#define _destroy_event(x) // do nothing -KLIST_INIT(Event, Event, _destroy_event) - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/event.c.generated.h" -#endif -// deferred_events: Events that should be processed as the K_EVENT special key -// immediate_events: Events that should be processed after exiting libuv event -// loop(to avoid recursion), but before returning from -// `event_poll` -static klist_t(Event) *deferred_events = NULL, *immediate_events = NULL; -static int deferred_events_allowed = 0; - -void event_init(void) -{ - // Initialize the event queues - deferred_events = kl_init(Event); - immediate_events = kl_init(Event); - // early msgpack-rpc initialization - msgpack_rpc_init_method_table(); - msgpack_rpc_helpers_init(); - // Initialize input events - input_init(); - // Timer to wake the event loop if a timeout argument is passed to - // `event_poll` - // Signals - signal_init(); - // Jobs - job_init(); - // finish mspgack-rpc initialization - channel_init(); - server_init(); - terminal_init(); -} - -void event_teardown(void) -{ - if (!deferred_events) { - // Not initialized(possibly a --version invocation) - return; - } - - process_events_from(immediate_events); - process_events_from(deferred_events); - input_stop(); - channel_teardown(); - job_teardown(); - server_teardown(); - signal_teardown(); - terminal_teardown(); - - // this last `uv_run` will return after all handles are stopped, it will - // also take care of finishing any uv_close calls made by other *_teardown - // functions. - do { - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - } while (uv_loop_close(uv_default_loop())); -} - -// Wait for some event -void event_poll(int ms) -{ - static int recursive = 0; - - if (recursive++) { - abort(); // Should not re-enter uv_run - } - - uv_run_mode run_mode = UV_RUN_ONCE; - uv_timer_t timer; - - if (ms > 0) { - uv_timer_init(uv_default_loop(), &timer); - // Use a repeating timeout of ms milliseconds to make sure - // we do not block indefinitely for I/O. - uv_timer_start(&timer, timer_cb, (uint64_t)ms, (uint64_t)ms); - } else if (ms == 0) { - // For ms == 0, we need to do a non-blocking event poll by - // setting the run mode to UV_RUN_NOWAIT. - run_mode = UV_RUN_NOWAIT; - } - - loop(run_mode); - - if (ms > 0) { - // Ensure the timer handle is closed and run the event loop - // once more to let libuv perform it's cleanup - uv_timer_stop(&timer); - uv_close((uv_handle_t *)&timer, NULL); - loop(UV_RUN_NOWAIT); - } - - recursive--; // Can re-enter uv_run now - - // In case this is run before event_init, don't process any events. - if (immediate_events) { - process_events_from(immediate_events); - } -} - -bool event_has_deferred(void) -{ - return deferred_events_allowed && !kl_empty(deferred_events); -} - -void event_enable_deferred(void) -{ - ++deferred_events_allowed; -} - -void event_disable_deferred(void) -{ - --deferred_events_allowed; -} - -// Queue an event -void event_push(Event event, bool deferred) -{ - // Sometimes libuv will run pending callbacks(timer for example) before - // blocking for a poll. If this happens and the callback pushes a event to one - // of the queues, the event would only be processed after the poll - // returns(user hits a key for example). To avoid this scenario, we call - // uv_stop when a event is enqueued. - uv_stop(uv_default_loop()); - kl_push(Event, deferred ? deferred_events : immediate_events, event); -} - -void event_process(void) -{ - process_events_from(deferred_events); -} - -static void process_events_from(klist_t(Event) *queue) -{ - while (!kl_empty(queue)) { - Event event = kl_shift(Event, queue); - event.handler(event); - } -} - -static void timer_cb(uv_timer_t *handle) -{ -} - -static void loop(uv_run_mode run_mode) -{ - DLOG("Enter event loop"); - uv_run(uv_default_loop(), run_mode); - DLOG("Exit event loop"); -} diff --git a/src/nvim/os/event_defs.h b/src/nvim/os/event_defs.h deleted file mode 100644 index 2dd9403d9f..0000000000 --- a/src/nvim/os/event_defs.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef NVIM_OS_EVENT_DEFS_H -#define NVIM_OS_EVENT_DEFS_H - -#include <stdbool.h> - -#include "nvim/os/job_defs.h" -#include "nvim/os/rstream_defs.h" - -typedef struct event Event; -typedef void (*event_handler)(Event event); - -struct event { - void *data; - event_handler handler; -}; - -#endif // NVIM_OS_EVENT_DEFS_H diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 726335bd9a..1449c56d59 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -6,7 +6,7 @@ #include "nvim/api/private/defs.h" #include "nvim/os/input.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/rstream.h" #include "nvim/ascii.h" @@ -115,7 +115,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) } // If there are deferred events, return the keys directly - if (event_has_deferred()) { + if (loop_has_deferred_events(&loop)) { return push_event_key(buf, maxlen); } @@ -136,7 +136,7 @@ bool os_char_avail(void) void os_breakcheck(void) { if (!disable_breakcheck && !got_int) { - event_poll(0); + loop_poll_events(&loop, 0); } } @@ -285,7 +285,7 @@ static bool input_poll(int ms) prof_inchar_enter(); } - event_poll_until(ms, input_ready() || input_eof); + LOOP_POLL_EVENTS_UNTIL(&loop, ms, input_ready() || input_eof); if (do_profiling == PROF_YES && ms) { prof_inchar_exit(); @@ -362,7 +362,7 @@ static bool input_ready(void) { return typebuf_was_filled || // API call filled typeahead rbuffer_size(input_buffer) || // Input buffer filled - event_has_deferred(); // Events must be processed + loop_has_deferred_events(&loop); // Events must be processed } // Exit because of an input read error. diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c index f9bde21361..7e90994fb3 100644 --- a/src/nvim/os/job.c +++ b/src/nvim/os/job.c @@ -3,6 +3,9 @@ #include <uv.h> +#include "nvim/event/loop.h" +#include "nvim/event/time.h" +#include "nvim/event/signal.h" #include "nvim/os/uv_helpers.h" #include "nvim/os/job.h" #include "nvim/os/job_defs.h" @@ -12,8 +15,6 @@ #include "nvim/os/rstream_defs.h" #include "nvim/os/wstream.h" #include "nvim/os/wstream_defs.h" -#include "nvim/os/event.h" -#include "nvim/os/event_defs.h" #include "nvim/os/time.h" #include "nvim/vim.h" #include "nvim/memory.h" @@ -45,8 +46,8 @@ Job *table[MAX_RUNNING_JOBS] = {NULL}; size_t stop_requests = 0; -uv_timer_t job_stop_timer; -uv_signal_t schld; +TimeWatcher job_stop_timer; +SignalWatcher schld; // Some helpers shared in this module @@ -59,9 +60,9 @@ uv_signal_t schld; void job_init(void) { uv_disable_stdio_inheritance(); - uv_timer_init(uv_default_loop(), &job_stop_timer); - uv_signal_init(uv_default_loop(), &schld); - uv_signal_start(&schld, chld_handler, SIGCHLD); + time_watcher_init(&loop, &job_stop_timer, NULL); + signal_watcher_init(&loop, &schld, NULL); + signal_watcher_start(&schld, chld_handler, SIGCHLD); } /// Releases job control resources and terminates running jobs @@ -78,11 +79,11 @@ void job_teardown(void) } // Wait until all jobs are closed - event_poll_until(-1, !stop_requests); - uv_signal_stop(&schld); - uv_close((uv_handle_t *)&schld, NULL); + LOOP_POLL_EVENTS_UNTIL(&loop, -1, !stop_requests); + signal_watcher_stop(&schld); + signal_watcher_close(&schld, NULL); // Close the timer - uv_close((uv_handle_t *)&job_stop_timer, NULL); + time_watcher_close(&job_stop_timer, NULL); } /// Tries to start a new job. @@ -152,7 +153,7 @@ Job *job_start(JobOptions opts, int *status) uv_close((uv_handle_t *)job->proc_stderr, close_cb); } process_close(job); - event_poll(0); + loop_poll_events(&loop, 0); // Manually invoke the close_cb to free the job resources *status = -1; return NULL; @@ -223,7 +224,7 @@ void job_stop(Job *job) // When there's at least one stop request pending, start a timer that // will periodically check if a signal should be send to a to the job DLOG("Starting job kill timer"); - uv_timer_start(&job_stop_timer, job_stop_timer_cb, 100, 100); + time_watcher_start(&job_stop_timer, job_stop_timer_cb, 100, 100); } } @@ -245,7 +246,7 @@ int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL // Increase refcount to stop the job from being freed before we have a // chance to get the status. job->refcount++; - event_poll_until(ms, + LOOP_POLL_EVENTS_UNTIL(&loop, ms, // Until... got_int || // interrupted by the user job->refcount == 1); // job exited @@ -259,9 +260,9 @@ int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL if (ms == -1) { // We can only return, if all streams/handles are closed and the job // exited. - event_poll_until(-1, job->refcount == 1); + LOOP_POLL_EVENTS_UNTIL(&loop, -1, job->refcount == 1); } else { - event_poll(0); + loop_poll_events(&loop, 0); } } @@ -379,7 +380,7 @@ JobOptions *job_opts(Job *job) /// Iterates the table, sending SIGTERM to stopped jobs and SIGKILL to those /// that didn't die from SIGTERM after a while(exit_timeout is 0). -static void job_stop_timer_cb(uv_timer_t *handle) +static void job_stop_timer_cb(TimeWatcher *watcher, void *data) { Job *job; uint64_t now = os_hrtime(); @@ -432,7 +433,7 @@ static void job_exited(Event event) process_close(job); } -static void chld_handler(uv_signal_t *handle, int signum) +static void chld_handler(SignalWatcher *watcher, int signum, void *data) { int stat = 0; int pid; @@ -458,7 +459,8 @@ static void chld_handler(uv_signal_t *handle, int signum) // don't enqueue more events when exiting process_close(job); } else { - event_push((Event) {.handler = job_exited, .data = job}, false); + loop_push_event(&loop, + (Event) {.handler = job_exited, .data = job}, false); } break; } diff --git a/src/nvim/os/job.h b/src/nvim/os/job.h index e0ca615626..ed102666d0 100644 --- a/src/nvim/os/job.h +++ b/src/nvim/os/job.h @@ -11,7 +11,7 @@ #include <stdbool.h> #include "nvim/os/rstream_defs.h" -#include "nvim/os/event_defs.h" +#include "nvim/os/job_defs.h" #include "nvim/os/wstream.h" #include "nvim/os/wstream_defs.h" diff --git a/src/nvim/os/job_private.h b/src/nvim/os/job_private.h index 983106d918..b90f2d0171 100644 --- a/src/nvim/os/job_private.h +++ b/src/nvim/os/job_private.h @@ -5,6 +5,7 @@ #include <uv.h> +#include "nvim/event/time.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/wstream_defs.h" #include "nvim/os/pipe_process.h" @@ -43,7 +44,7 @@ struct job { extern Job *table[]; extern size_t stop_requests; -extern uv_timer_t job_stop_timer; +extern TimeWatcher job_stop_timer; static inline bool process_spawn(Job *job) { @@ -95,7 +96,7 @@ static inline void job_exit_callback(Job *job) if (stop_requests && !--stop_requests) { // Stop the timer if no more stop requests are pending DLOG("Stopping job kill timer"); - uv_timer_stop(&job_stop_timer); + time_watcher_stop(&job_stop_timer); } } diff --git a/src/nvim/os/pipe_process.c b/src/nvim/os/pipe_process.c index 2ac305e967..9980cf7c56 100644 --- a/src/nvim/os/pipe_process.c +++ b/src/nvim/os/pipe_process.c @@ -9,6 +9,8 @@ #include "nvim/os/job_private.h" #include "nvim/os/pipe_process.h" #include "nvim/memory.h" +#include "nvim/vim.h" +#include "nvim/globals.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/pipe_process.c.generated.h" @@ -46,19 +48,19 @@ void pipe_process_init(Job *job) handle_set_job((uv_handle_t *)&pipeproc->proc, job); if (job->opts.writable) { - uv_pipe_init(uv_default_loop(), &pipeproc->proc_stdin, 0); + uv_pipe_init(&loop.uv, &pipeproc->proc_stdin, 0); pipeproc->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; pipeproc->stdio[0].data.stream = (uv_stream_t *)&pipeproc->proc_stdin; } if (job->opts.stdout_cb) { - uv_pipe_init(uv_default_loop(), &pipeproc->proc_stdout, 0); + uv_pipe_init(&loop.uv, &pipeproc->proc_stdout, 0); pipeproc->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; pipeproc->stdio[1].data.stream = (uv_stream_t *)&pipeproc->proc_stdout; } if (job->opts.stderr_cb) { - uv_pipe_init(uv_default_loop(), &pipeproc->proc_stderr, 0); + uv_pipe_init(&loop.uv, &pipeproc->proc_stderr, 0); pipeproc->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; pipeproc->stdio[2].data.stream = (uv_stream_t *)&pipeproc->proc_stderr; } @@ -81,7 +83,7 @@ bool pipe_process_spawn(Job *job) { UvProcess *pipeproc = job->process; - if (uv_spawn(uv_default_loop(), &pipeproc->proc, &pipeproc->proc_opts) != 0) { + if (uv_spawn(&loop.uv, &pipeproc->proc, &pipeproc->proc_opts) != 0) { return false; } diff --git a/src/nvim/os/pty_process.c b/src/nvim/os/pty_process.c index ff0bcfb6de..ca74ebfddd 100644 --- a/src/nvim/os/pty_process.c +++ b/src/nvim/os/pty_process.c @@ -26,6 +26,8 @@ #include "nvim/os/job_private.h" #include "nvim/os/pty_process.h" #include "nvim/memory.h" +#include "nvim/vim.h" +#include "nvim/globals.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/pty_process.c.generated.h" @@ -43,17 +45,17 @@ void pty_process_init(Job *job) FUNC_ATTR_NONNULL_ALL ptyproc->tty_fd = -1; if (job->opts.writable) { - uv_pipe_init(uv_default_loop(), &ptyproc->proc_stdin, 0); + uv_pipe_init(&loop.uv, &ptyproc->proc_stdin, 0); ptyproc->proc_stdin.data = NULL; } if (job->opts.stdout_cb) { - uv_pipe_init(uv_default_loop(), &ptyproc->proc_stdout, 0); + uv_pipe_init(&loop.uv, &ptyproc->proc_stdout, 0); ptyproc->proc_stdout.data = NULL; } if (job->opts.stderr_cb) { - uv_pipe_init(uv_default_loop(), &ptyproc->proc_stderr, 0); + uv_pipe_init(&loop.uv, &ptyproc->proc_stderr, 0); ptyproc->proc_stderr.data = NULL; } diff --git a/src/nvim/os/rstream.c b/src/nvim/os/rstream.c index af84288f0f..dd91c2777e 100644 --- a/src/nvim/os/rstream.c +++ b/src/nvim/os/rstream.c @@ -120,7 +120,7 @@ void rstream_set_file(RStream *rstream, uv_file file) // in chunks of rstream->buffer_size, giving time for other events to // be processed between reads. rstream->fread_idle = xmalloc(sizeof(uv_idle_t)); - uv_idle_init(uv_default_loop(), rstream->fread_idle); + uv_idle_init(&loop.uv, rstream->fread_idle); rstream->fread_idle->data = NULL; handle_set_rstream((uv_handle_t *)rstream->fread_idle, rstream); } else { @@ -128,7 +128,7 @@ void rstream_set_file(RStream *rstream, uv_file file) assert(rstream->file_type == UV_NAMED_PIPE || rstream->file_type == UV_TTY); rstream->stream = xmalloc(sizeof(uv_pipe_t)); - uv_pipe_init(uv_default_loop(), (uv_pipe_t *)rstream->stream, 0); + uv_pipe_init(&loop.uv, (uv_pipe_t *)rstream->stream, 0); uv_pipe_open((uv_pipe_t *)rstream->stream, file); rstream->stream->data = NULL; handle_set_rstream((uv_handle_t *)rstream->stream, rstream); @@ -224,7 +224,7 @@ static void fread_idle_cb(uv_idle_t *handle) // Synchronous read uv_fs_read( - uv_default_loop(), + &loop.uv, &req, rstream->fd, &rstream->uvbuf, diff --git a/src/nvim/os/rstream.h b/src/nvim/os/rstream.h index 3e24724573..7da77b33fa 100644 --- a/src/nvim/os/rstream.h +++ b/src/nvim/os/rstream.h @@ -4,7 +4,6 @@ #include <stdbool.h> #include <stdint.h> #include <uv.h> -#include "nvim/os/event_defs.h" #include "nvim/os/rstream_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 48174533a6..9c0d5fca67 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -8,7 +8,7 @@ #include "nvim/ascii.h" #include "nvim/lib/kvec.h" #include "nvim/log.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/job.h" #include "nvim/os/rstream.h" #include "nvim/os/shell.h" diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index f824543003..6de3435c4c 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -11,12 +11,13 @@ #include "nvim/memory.h" #include "nvim/misc1.h" #include "nvim/misc2.h" +#include "nvim/event/signal.h" #include "nvim/os/signal.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" -static uv_signal_t spipe, shup, squit, sterm; +static SignalWatcher spipe, shup, squit, sterm; #ifdef SIGPWR -static uv_signal_t spwr; +static SignalWatcher spwr; #endif static bool rejecting_deadly; @@ -27,40 +28,40 @@ static bool rejecting_deadly; void signal_init(void) { - uv_signal_init(uv_default_loop(), &spipe); - uv_signal_init(uv_default_loop(), &shup); - uv_signal_init(uv_default_loop(), &squit); - uv_signal_init(uv_default_loop(), &sterm); - uv_signal_start(&spipe, signal_cb, SIGPIPE); - uv_signal_start(&shup, signal_cb, SIGHUP); - uv_signal_start(&squit, signal_cb, SIGQUIT); - uv_signal_start(&sterm, signal_cb, SIGTERM); + signal_watcher_init(&loop, &spipe, NULL); + signal_watcher_init(&loop, &shup, NULL); + signal_watcher_init(&loop, &squit, NULL); + signal_watcher_init(&loop, &sterm, NULL); + signal_watcher_start(&spipe, on_signal, SIGPIPE); + signal_watcher_start(&shup, on_signal, SIGHUP); + signal_watcher_start(&squit, on_signal, SIGQUIT); + signal_watcher_start(&sterm, on_signal, SIGTERM); #ifdef SIGPWR - uv_signal_init(uv_default_loop(), &spwr); - uv_signal_start(&spwr, signal_cb, SIGPWR); + signal_watcher_init(&loop, &spwr, NULL); + signal_watcher_start(&spwr, on_signal, SIGPWR); #endif } void signal_teardown(void) { signal_stop(); - uv_close((uv_handle_t *)&spipe, NULL); - uv_close((uv_handle_t *)&shup, NULL); - uv_close((uv_handle_t *)&squit, NULL); - uv_close((uv_handle_t *)&sterm, NULL); + signal_watcher_close(&spipe, NULL); + signal_watcher_close(&shup, NULL); + signal_watcher_close(&squit, NULL); + signal_watcher_close(&sterm, NULL); #ifdef SIGPWR - uv_close((uv_handle_t *)&spwr, NULL); + signal_watcher_close(&spwr, NULL); #endif } void signal_stop(void) { - uv_signal_stop(&spipe); - uv_signal_stop(&shup); - uv_signal_stop(&squit); - uv_signal_stop(&sterm); + signal_watcher_stop(&spipe); + signal_watcher_stop(&shup); + signal_watcher_stop(&squit); + signal_watcher_stop(&sterm); #ifdef SIGPWR - uv_signal_stop(&spwr); + signal_watcher_stop(&spwr); #endif } @@ -111,10 +112,10 @@ static void deadly_signal(int signum) preserve_exit(); } -static void signal_cb(uv_signal_t *handle, int signum) +static void on_signal(SignalWatcher *handle, int signum, void *data) { assert(signum >= 0); - event_push((Event) { + loop_push_event(&loop, (Event) { .handler = on_signal_event, .data = (void *)(uintptr_t)signum }, false); diff --git a/src/nvim/os/signal.h b/src/nvim/os/signal.h index 927437b2db..5d8cc6f661 100644 --- a/src/nvim/os/signal.h +++ b/src/nvim/os/signal.h @@ -1,8 +1,6 @@ #ifndef NVIM_OS_SIGNAL_H #define NVIM_OS_SIGNAL_H -#include "nvim/os/event_defs.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/signal.h.generated.h" #endif diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 590dfba797..6b5d4359db 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -7,7 +7,7 @@ #include <uv.h> #include "nvim/os/time.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/vim.h" static uv_mutex_t delay_mutex; @@ -43,7 +43,7 @@ void os_delay(uint64_t milliseconds, bool ignoreinput) if (milliseconds > INT_MAX) { milliseconds = INT_MAX; } - event_poll_until((int)milliseconds, got_int); + LOOP_POLL_EVENTS_UNTIL(&loop, (int)milliseconds, got_int); } else { os_microdelay(milliseconds * 1000); } diff --git a/src/nvim/os/wstream.c b/src/nvim/os/wstream.c index 73896c381d..7f5191947a 100644 --- a/src/nvim/os/wstream.c +++ b/src/nvim/os/wstream.c @@ -103,7 +103,7 @@ void wstream_set_file(WStream *wstream, uv_file file) assert(uv_guess_handle(file) == UV_NAMED_PIPE || uv_guess_handle(file) == UV_TTY); wstream->stream = xmalloc(sizeof(uv_pipe_t)); - uv_pipe_init(uv_default_loop(), (uv_pipe_t *)wstream->stream, 0); + uv_pipe_init(&loop.uv, (uv_pipe_t *)wstream->stream, 0); uv_pipe_open((uv_pipe_t *)wstream->stream, file); wstream->stream->data = NULL; handle_set_wstream((uv_handle_t *)wstream->stream, wstream); diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index ccd0073db1..f568f5a7f1 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -47,13 +47,11 @@ #include "nvim/types.h" #include "nvim/os/os.h" #include "nvim/os/time.h" -#include "nvim/os/event.h" #include "nvim/os/input.h" #include "nvim/os/shell.h" #include "nvim/os/signal.h" #include "nvim/os/job.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/msgpack_rpc/defs.h" #ifdef HAVE_STROPTS_H # include <stropts.h> diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 9ce050ed7a..47fef692db 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -67,7 +67,8 @@ #include "nvim/ex_cmds.h" #include "nvim/window.h" #include "nvim/fileio.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" +#include "nvim/event/time.h" #include "nvim/api/private/helpers.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -80,7 +81,7 @@ // of data. #define REFRESH_DELAY 10 -static uv_timer_t refresh_timer; +static TimeWatcher refresh_timer; static bool refresh_pending = false; typedef struct { @@ -150,7 +151,7 @@ static VTermColor default_vt_bg_rgb; void terminal_init(void) { invalidated_terminals = pmap_new(ptr_t)(); - uv_timer_init(uv_default_loop(), &refresh_timer); + time_watcher_init(&loop, &refresh_timer, NULL); // initialize a rgb->color index map for cterm attributes(VTermScreenCell // only has RGB information and we need color indexes for terminal UIs) @@ -175,8 +176,8 @@ void terminal_init(void) void terminal_teardown(void) { - uv_timer_stop(&refresh_timer); - uv_close((uv_handle_t *)&refresh_timer, NULL); + time_watcher_stop(&refresh_timer); + time_watcher_close(&refresh_timer, NULL); pmap_free(ptr_t)(invalidated_terminals); map_free(int, int)(color_indexes); } @@ -353,13 +354,13 @@ void terminal_enter(bool process_deferred) while (term->buf == curbuf) { if (process_deferred) { - event_enable_deferred(); + loop_enable_deferred_events(&loop); } c = safe_vgetc(); if (process_deferred) { - event_disable_deferred(); + loop_disable_deferred_events(&loop); } switch (c) { @@ -380,7 +381,7 @@ void terminal_enter(bool process_deferred) break; case K_EVENT: - event_process(); + loop_process_event(&loop); break; case Ctrl_N: @@ -877,16 +878,16 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row) pmap_put(ptr_t)(invalidated_terminals, term, NULL); if (!refresh_pending) { - uv_timer_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0); + time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0); refresh_pending = true; } } // libuv timer callback. This will enqueue on_refresh to be processed as an // event. -static void refresh_timer_cb(uv_timer_t *handle) +static void refresh_timer_cb(TimeWatcher *watcher, void *data) { - event_push((Event) {.handler = on_refresh}, false); + loop_push_event(&loop, (Event) {.handler = on_refresh}, false); refresh_pending = false; } diff --git a/src/nvim/tui/term_input.inl b/src/nvim/tui/term_input.inl index efdcf0a41e..331a0a89e0 100644 --- a/src/nvim/tui/term_input.inl +++ b/src/nvim/tui/term_input.inl @@ -5,6 +5,7 @@ #include "nvim/os/os.h" #include "nvim/os/input.h" #include "nvim/os/rstream.h" +#include "nvim/event/time.h" #define PASTETOGGLE_KEY "<f37>" @@ -12,7 +13,7 @@ struct term_input { int in_fd; bool paste_enabled; TermKey *tk; - uv_timer_t timer_handle; + TimeWatcher timer_handle; RBuffer *read_buffer; RStream *read_stream; }; @@ -107,7 +108,7 @@ static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force) return force ? termkey_getkey_force(tk, key) : termkey_getkey(tk, key); } -static void timer_cb(uv_timer_t *handle); +static void timer_cb(TimeWatcher *watcher, void *data); static int get_key_code_timeout(void) { @@ -147,17 +148,16 @@ static void tk_getkeys(TermInput *input, bool force) if (ms > 0) { // Stop the current timer if already running - uv_timer_stop(&input->timer_handle); - uv_timer_start(&input->timer_handle, timer_cb, (uint32_t)ms, 0); + time_watcher_stop(&input->timer_handle); + time_watcher_start(&input->timer_handle, timer_cb, (uint32_t)ms, 0); } else { tk_getkeys(input, true); } } - -static void timer_cb(uv_timer_t *handle) +static void timer_cb(TimeWatcher *watcher, void *data) { - tk_getkeys(handle->data, true); + tk_getkeys(data, true); } static bool handle_bracketed_paste(TermInput *input) @@ -288,8 +288,7 @@ static TermInput *term_input_new(void) rstream_set_file(rv->read_stream, rv->in_fd); rstream_start(rv->read_stream); // initialize a timer handle for handling ESC with libtermkey - uv_timer_init(uv_default_loop(), &rv->timer_handle); - rv->timer_handle.data = rv; + time_watcher_init(&loop, &rv->timer_handle, rv); // Set the pastetoggle option to a special key that will be sent when // \e[20{0,1}~/ are received Error err = ERROR_INIT; @@ -300,12 +299,13 @@ static TermInput *term_input_new(void) static void term_input_destroy(TermInput *input) { - uv_timer_stop(&input->timer_handle); + time_watcher_stop(&input->timer_handle); + time_watcher_close(&input->timer_handle, NULL); rstream_stop(input->read_stream); rstream_free(input->read_stream); - uv_close((uv_handle_t *)&input->timer_handle, NULL); termkey_destroy(input->tk); - event_poll(0); // Run once to remove references to input/timer handles + // Run once to remove references to input/timer handles + loop_poll_events(&loop, 0); xfree(input); } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fe29dbd961..a12ee880d6 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -13,7 +13,8 @@ #include "nvim/memory.h" #include "nvim/api/vim.h" #include "nvim/api/private/helpers.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" +#include "nvim/event/signal.h" #include "nvim/tui/tui.h" #include "nvim/strings.h" @@ -43,7 +44,7 @@ typedef struct { uv_loop_t *write_loop; unibi_term *ut; uv_tty_t output_handle; - uv_signal_t winch_handle; + SignalWatcher winch_handle; Rect scroll_region; kvec_t(Rect) invalid_regions; int row, col; @@ -132,9 +133,8 @@ UI *tui_start(void) update_size(ui); // listen for SIGWINCH - uv_signal_init(uv_default_loop(), &data->winch_handle); - uv_signal_start(&data->winch_handle, sigwinch_cb, SIGWINCH); - data->winch_handle.data = ui; + signal_watcher_init(&loop, &data->winch_handle, ui); + signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH); ui->stop = tui_stop; ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL; @@ -172,8 +172,8 @@ static void tui_stop(UI *ui) TUIData *data = ui->data; // Destroy common stuff kv_destroy(data->invalid_regions); - uv_signal_stop(&data->winch_handle); - uv_close((uv_handle_t *)&data->winch_handle, NULL); + signal_watcher_stop(&data->winch_handle); + signal_watcher_close(&data->winch_handle, NULL); // Destroy input stuff term_input_destroy(data->input); // Destroy output stuff @@ -207,12 +207,12 @@ static void try_resize(Event ev) ui_refresh(); } -static void sigwinch_cb(uv_signal_t *handle, int signum) +static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data) { // Queue the event because resizing can result in recursive event_poll calls // FIXME(blueyed): TUI does not resize properly when not deferred. Why? #2322 - event_push((Event) { - .data = handle->data, + loop_push_event(&loop, (Event) { + .data = data, .handler = try_resize }, true); } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 088055777a..dc2bc0898c 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -23,7 +23,7 @@ #include "nvim/normal.h" #include "nvim/option.h" #include "nvim/os_unix.h" -#include "nvim/os/event.h" +#include "nvim/event/loop.h" #include "nvim/os/time.h" #include "nvim/os/input.h" #include "nvim/os/signal.h" @@ -216,7 +216,7 @@ void ui_detach(UI *ui) ui_count--; // schedule a refresh - event_push((Event) { .handler = refresh }, false); + loop_push_event(&loop, (Event) { .handler = refresh }, false); } void ui_clear(void) diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 3d5c6bc885..2ffffb907f 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -19,7 +19,7 @@ require('bit') cimport('unistd.h') cimport('./src/nvim/os/shell.h') cimport('./src/nvim/option_defs.h') -cimport('./src/nvim/os/event.h') +cimport('./src/nvim/main.h') cimport('./src/nvim/fileio.h') local fs = cimport('./src/nvim/os/os.h') cppimport('sys/stat.h') diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua index 91d807da0b..91123bfd58 100644 --- a/test/unit/os/shell_spec.lua +++ b/test/unit/os/shell_spec.lua @@ -14,7 +14,7 @@ local helpers = require('test.unit.helpers') local shell = helpers.cimport( './src/nvim/os/shell.h', './src/nvim/option_defs.h', - './src/nvim/os/event.h', + './src/nvim/main.h', './src/nvim/misc1.h' ) local ffi, eq, neq = helpers.ffi, helpers.eq, helpers.neq |