diff options
Diffstat (limited to 'src/nvim/os/event.c')
-rw-r--r-- | src/nvim/os/event.c | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c index 6367a60af7..a460b2db96 100644 --- a/src/nvim/os/event.c +++ b/src/nvim/os/event.c @@ -33,6 +33,11 @@ typedef struct { # include "os/event.c.generated.h" #endif static klist_t(Event) *deferred_events, *immediate_events; +// NULL-terminated array of event sources that we should process immediately. +// +// Events from sources that are not contained in this array are processed +// later when `event_process` is called +static EventSource *immediate_sources = NULL; void event_init(void) { @@ -63,7 +68,8 @@ void event_teardown(void) } // Wait for some event -bool event_poll(int32_t ms) +bool event_poll(int32_t ms, EventSource sources[]) + FUNC_ATTR_NONNULL_ARG(2) { uv_run_mode run_mode = UV_RUN_ONCE; @@ -99,10 +105,7 @@ bool event_poll(int32_t ms) do { // Run one event loop iteration, blocking for events if run_mode is // UV_RUN_ONCE - DLOG("Entering event loop"); - uv_run(uv_default_loop(), run_mode); - processed_events = event_process(false); - DLOG("Exited event loop, processed %u events", processed_events); + processed_events = loop(run_mode, sources); } while ( // Continue running if ... !processed_events && // we didn't process any immediate events @@ -120,8 +123,7 @@ bool event_poll(int32_t ms) // 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); + processed_events += loop(UV_RUN_NOWAIT, sources); } return !timer_data.timed_out && (processed_events || event_has_deferred()); @@ -129,22 +131,41 @@ bool event_poll(int32_t ms) bool event_has_deferred(void) { - return !kl_empty(get_queue(true)); + return !kl_empty(deferred_events); } -// Push an event to the queue -void event_push(Event event, bool deferred) +// Queue an event +void event_push(Event event) { - *kl_pushp(Event, get_queue(deferred)) = event; + bool defer = true; + + if (immediate_sources) { + size_t i; + EventSource src; + + for (src = immediate_sources[i = 0]; src; src = immediate_sources[++i]) { + if (src == event.source) { + defer = false; + break; + } + } + } + + *kl_pushp(Event, defer ? deferred_events : immediate_events) = event; +} + +void event_process(void) +{ + process_from(deferred_events); } // Runs the appropriate action for each queued event -size_t event_process(bool deferred) +static size_t process_from(klist_t(Event) *queue) { size_t count = 0; Event event; - while (kl_shift(Event, get_queue(deferred), &event) == 0) { + while (kl_shift(Event, queue, &event) == 0) { switch (event.type) { case kEventSignal: signal_handle(event); @@ -161,6 +182,8 @@ size_t event_process(bool deferred) count++; } + DLOG("Processed %u events", count); + return count; } @@ -179,7 +202,42 @@ static void timer_prepare_cb(uv_prepare_t *handle) uv_prepare_stop(handle); } -static klist_t(Event) *get_queue(bool deferred) +static void requeue_deferred_events(void) { - return deferred ? deferred_events : immediate_events; + size_t remaining = deferred_events->size; + + DLOG("Number of deferred events: %u", remaining); + + while (remaining--) { + // Re-push each deferred event to ensure it will be in the right queue + Event event; + kl_shift(Event, deferred_events, &event); + event_push(event); + DLOG("Re-queueing event"); + } + + DLOG("Number of deferred events: %u", deferred_events->size); +} + +static size_t loop(uv_run_mode run_mode, EventSource *sources) +{ + size_t count; + immediate_sources = sources; + // It's possible that some events from the immediate sources are waiting + // in the deferred queue. If so, move them to the immediate queue so they + // will be processed in order of arrival by the next `process_from` call. + requeue_deferred_events(); + count = process_from(immediate_events); + + if (count) { + // No need to enter libuv, events were already processed + return count; + } + + DLOG("Enter event loop"); + uv_run(uv_default_loop(), run_mode); + DLOG("Exit event loop"); + immediate_sources = NULL; + count = process_from(immediate_events); + return count; } |