diff options
Diffstat (limited to 'src/nvim/os/event.c')
-rw-r--r-- | src/nvim/os/event.c | 87 |
1 files changed, 59 insertions, 28 deletions
diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c index 2ebf28f436..6723b97e0c 100644 --- a/src/nvim/os/event.c +++ b/src/nvim/os/event.c @@ -21,17 +21,22 @@ #define _destroy_event(x) // do nothing KLIST_INIT(Event, Event, _destroy_event) +typedef struct { + bool timed_out; + int32_t ms; + uv_timer_t *timer; +} TimerData; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/event.c.generated.h" #endif -static klist_t(Event) *event_queue; -static uv_timer_t timer; -static uv_prepare_t timer_prepare; +static klist_t(Event) *deferred_events, *immediate_events; void event_init() { - // Initialize the event queue - event_queue = kl_init(Event); + // Initialize the event queues + deferred_events = kl_init(Event); + immediate_events = kl_init(Event); // Initialize input events input_init(); // Timer to wake the event loop if a timeout argument is passed to @@ -44,9 +49,6 @@ void event_init() channel_init(); // Servers server_init(); - uv_timer_init(uv_default_loop(), &timer); - // This prepare handle that actually starts the timer - uv_prepare_init(uv_default_loop(), &timer_prepare); } void event_teardown() @@ -59,7 +61,6 @@ void event_teardown() // Wait for some event bool event_poll(int32_t ms) { - bool timed_out; uv_run_mode run_mode = UV_RUN_ONCE; if (input_ready()) { @@ -67,15 +68,26 @@ bool event_poll(int32_t ms) return true; } - input_start(); - timed_out = false; + static int recursive = 0; + + if (!(recursive++)) { + // Only needs to start the libuv handle the first time we enter here + input_start(); + } + + uv_timer_t timer; + uv_prepare_t timer_prepare; + TimerData timer_data = {.ms = ms, .timed_out = false, .timer = &timer}; if (ms > 0) { + uv_timer_init(uv_default_loop(), &timer); + // This prepare handle that actually starts the timer + uv_prepare_init(uv_default_loop(), &timer_prepare); // Timeout passed as argument to the timer - timer.data = &timed_out; + timer.data = &timer_data; // We only start the timer after the loop is running, for that we // use a prepare handle(pass the interval as data to it) - timer_prepare.data = &ms; + timer_prepare.data = &timer_data; uv_prepare_start(&timer_prepare, timer_prepare_cb); } else if (ms == 0) { // For ms == 0, we need to do a non-blocking event poll by @@ -87,40 +99,51 @@ bool event_poll(int32_t ms) // Run one event loop iteration, blocking for events if run_mode is // UV_RUN_ONCE uv_run(uv_default_loop(), run_mode); + // Process immediate events outside uv_run since libuv event loop not + // support recursion(processing events may cause a recursive event_poll + // call) + event_process(false); } while ( // Continue running if ... !input_ready() && // we have no input - kl_empty(event_queue) && // no events are waiting to be processed + !event_has_deferred() && // no events are waiting to be processed run_mode != UV_RUN_NOWAIT && // ms != 0 - !timed_out); // we didn't get a timeout + !timer_data.timed_out); // we didn't get a timeout - input_stop(); + if (!(--recursive)) { + // Again, only stop when we leave the top-level invocation + input_stop(); + } if (ms > 0) { - // Stop the timer - uv_timer_stop(&timer); + // Ensure the timer-related handles are closed and run the event loop + // once more to let libuv perform it's cleanup + uv_close((uv_handle_t *)&timer, NULL); + uv_close((uv_handle_t *)&timer_prepare, NULL); + uv_run(uv_default_loop(), UV_RUN_NOWAIT); + event_process(false); } - return input_ready() || event_is_pending(); + return input_ready() || event_has_deferred(); } -bool event_is_pending() +bool event_has_deferred() { - return !kl_empty(event_queue); + return !kl_empty(get_queue(true)); } // Push an event to the queue -void event_push(Event event) +void event_push(Event event, bool deferred) { - *kl_pushp(Event, event_queue) = event; + *kl_pushp(Event, get_queue(deferred)) = event; } // Runs the appropriate action for each queued event -void event_process() +void event_process(bool deferred) { Event event; - while (kl_shift(Event, event_queue, &event) == 0) { + while (kl_shift(Event, get_queue(deferred), &event) == 0) { switch (event.type) { case kEventSignal: signal_handle(event); @@ -140,11 +163,19 @@ void event_process() // Set a flag in the `event_poll` loop for signaling of a timeout static void timer_cb(uv_timer_t *handle) { - *((bool *)handle->data) = true; + TimerData *data = handle->data; + data->timed_out = true; } static void timer_prepare_cb(uv_prepare_t *handle) { - uv_timer_start(&timer, timer_cb, *(uint32_t *)timer_prepare.data, 0); - uv_prepare_stop(&timer_prepare); + TimerData *data = handle->data; + assert(data->ms > 0); + uv_timer_start(data->timer, timer_cb, (uint32_t)data->ms, 0); + uv_prepare_stop(handle); +} + +static klist_t(Event) *get_queue(bool deferred) +{ + return deferred ? deferred_events : immediate_events; } |