mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 05:58:33 +00:00
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.
This commit is contained in:
@@ -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)
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
137
src/nvim/event/loop.c
Normal file
137
src/nvim/event/loop.c
Normal file
@@ -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)
|
||||
{
|
||||
}
|
@@ -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
|
52
src/nvim/event/signal.c
Normal file
52
src/nvim/event/signal.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
22
src/nvim/event/signal.h
Normal file
22
src/nvim/event/signal.h
Normal file
@@ -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
|
55
src/nvim/event/time.c
Normal file
55
src/nvim/event/time.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
20
src/nvim/event/time.h
Normal file
20
src/nvim/event/time.h
Normal file
@@ -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
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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().
|
||||
|
@@ -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()`.
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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");
|
||||
}
|
@@ -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
|
@@ -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.
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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>
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user