diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-07-16 23:10:04 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-07-17 00:19:19 -0300 |
commit | 991d3ec1e679bb6407f2a5820910d2968424183c (patch) | |
tree | 38810fb657e1e1ea9d77b7a7963e874e8bda99d1 /src | |
parent | 9e42ef4e1312fb6888d2691e9d979b95dd43ec94 (diff) | |
download | rneovim-991d3ec1e679bb6407f2a5820910d2968424183c.tar.gz rneovim-991d3ec1e679bb6407f2a5820910d2968424183c.tar.bz2 rneovim-991d3ec1e679bb6407f2a5820910d2968424183c.zip |
event loop: New abstraction layer with refactored time/signal API
- Add event loop abstraction module under src/nvim/event. The
src/nvim/event/loop module replaces src/nvim/os/event
- Remove direct dependency on libuv signal/timer API and use the new abstraction
instead.
- Replace all references to uv_default_loop() by &loop.uv, a new global variable
that wraps libuv main event loop but allows the event loop functions to be
reused in other contexts.
Diffstat (limited to 'src')
36 files changed, 497 insertions, 336 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) |