aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os/event.c')
-rw-r--r--src/nvim/os/event.c87
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;
}