aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/event.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-11-02 16:37:08 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-11-02 16:47:50 -0300
commita1dd70b1d0e9ef155c81eeb249f137e763482d10 (patch)
treed80bf394168eb84f6eaf3630d091a40cf2b9e379 /src/nvim/os/event.c
parente378965a4483881c3f737eed5c3d24cb1f305a62 (diff)
downloadrneovim-a1dd70b1d0e9ef155c81eeb249f137e763482d10.tar.gz
rneovim-a1dd70b1d0e9ef155c81eeb249f137e763482d10.tar.bz2
rneovim-a1dd70b1d0e9ef155c81eeb249f137e763482d10.zip
event: Reintroduce the immediate event queue
Commit @264e0d872c("Remove automatic event deferral") removed the immediate event queue because event deferral now had to be explicit. The problem is that while some events don't need to be deferred, they still can result in recursive `event_poll` calls, and recursion is not supported by libuv. Examples of those are msgpack-rpc requests while a server->client request is pending, or signals which can call `mch_exit`(and that will result in `uv_run` calls). To fix the problem, this reintroduces the immediate event queue for events that can potentially result in event loop recursion. The non-deferred events are still processed in `event_poll`, but only after `uv_run` returns.
Diffstat (limited to 'src/nvim/os/event.c')
-rw-r--r--src/nvim/os/event.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c
index 657f1edad0..e09303e505 100644
--- a/src/nvim/os/event.c
+++ b/src/nvim/os/event.c
@@ -35,18 +35,24 @@ typedef struct {
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/event.c.generated.h"
#endif
-static klist_t(Event) *deferred_events;
+// 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, *immediate_events;
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();
wstream_init();
// Initialize input events
input_init();
+ input_start();
// Timer to wake the event loop if a timeout argument is passed to
// `event_poll`
// Signals
@@ -65,20 +71,19 @@ void event_teardown(void)
channel_teardown();
job_teardown();
server_teardown();
+ input_stop();
}
// Wait for some event
void event_poll(int ms)
{
- uv_run_mode run_mode = UV_RUN_ONCE;
-
static int recursive = 0;
- if (!(recursive++)) {
- // Only needs to start the libuv handle the first time we enter here
- input_start();
+ if (recursive++) {
+ abort(); // Should not re-enter uv_run
}
+ uv_run_mode run_mode = UV_RUN_ONCE;
uv_timer_t timer;
uv_prepare_t timer_prepare;
TimerData timer_data = {.ms = ms, .timed_out = false, .timer = &timer};
@@ -101,18 +106,18 @@ void event_poll(int ms)
loop(run_mode);
- if (!(--recursive)) {
- // Again, only stop when we leave the top-level invocation
- input_stop();
- }
-
if (ms > 0) {
// Ensure the timer-related handles are closed and run the event loop
// once more to let libuv perform it's cleanup
+ uv_timer_stop(&timer);
+ uv_prepare_stop(&timer_prepare);
uv_close((uv_handle_t *)&timer, NULL);
uv_close((uv_handle_t *)&timer_prepare, NULL);
loop(UV_RUN_NOWAIT);
}
+
+ recursive--; // Can re-enter uv_run now
+ process_events_from(immediate_events);
}
bool event_has_deferred(void)
@@ -121,17 +126,21 @@ bool event_has_deferred(void)
}
// Queue an event
-void event_push(Event event)
+void event_push(Event event, bool deferred)
{
- *kl_pushp(Event, deferred_events) = event;
+ *kl_pushp(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)
+{
Event event;
- while (kl_shift(Event, deferred_events, &event) == 0) {
+ while (kl_shift(Event, queue, &event) == 0) {
event.handler(event);
}
}