diff options
Diffstat (limited to 'src/os/event.c')
-rw-r--r-- | src/os/event.c | 105 |
1 files changed, 100 insertions, 5 deletions
diff --git a/src/os/event.c b/src/os/event.c index eb7960c219..943af8c24e 100644 --- a/src/os/event.c +++ b/src/os/event.c @@ -1,13 +1,26 @@ #include <stdint.h> #include <stdbool.h> +#include <stdlib.h> #include <uv.h> #include "os/event.h" #include "os/input.h" +#include "os/signal.h" +#include "vim.h" +#include "misc2.h" +typedef struct EventNode { + Event *event; + struct EventNode *next; +} EventNode; + +static EventNode *head, *tail; static uv_timer_t timer; static uv_prepare_t timer_prepare; +static bool poll_uv_loop(int ms); +static void process_all_events(void); +static bool has_pending_events(void); static void timer_cb(uv_timer_t *handle, int); static void timer_prepare_cb(uv_prepare_t *, int); @@ -17,14 +30,94 @@ void event_init() input_init(); // Timer to wake the event loop if a timeout argument is passed to // `event_poll` + // Signals + signal_init(); uv_timer_init(uv_default_loop(), &timer); // This prepare handle that actually starts the timer uv_prepare_init(uv_default_loop(), &timer_prepare); } -// Wait for some event bool event_poll(int32_t ms) { + int64_t remaining = ms; + uint64_t end; + bool result; + + if (ms > 0) { + // Calculate end time in nanoseconds + end = uv_hrtime() + ms * 1e6; + } + + for (;;) { + result = poll_uv_loop((int32_t)remaining); + // Process queued events + process_all_events(); + + if (ms > 0) { + // Calculate remaining time in milliseconds + remaining = (end - uv_hrtime()) / 1e6; + } + + if (input_ready() || got_int) { + // Bail out if we have pending input + return true; + } + + if (!result || (ms >= 0 && remaining <= 0)) { + // Or if we timed out + return false; + } + } +} + +// Push an event to the queue +void event_push(Event *event) +{ + EventNode *node = (EventNode *)xmalloc(sizeof(EventNode)); + node->event = event; + node->next = NULL; + + if (head == NULL) { + head = node; + } else { + tail->next = node; + } + + tail = node; +} + +// Runs the appropriate action for each queued event +static void process_all_events() +{ + EventNode *next; + Event *event; + + while (has_pending_events()) { + next = head->next; + event = head->event; + free(head); + head = next; + + switch (event->type) { + case kEventSignal: + signal_handle(event); + break; + default: + abort(); + } + + } +} + +// Checks if there are queued events +bool has_pending_events() +{ + return head != NULL; +} + +// Wait for some event +static bool poll_uv_loop(int32_t ms) +{ bool timed_out; uv_run_mode run_mode = UV_RUN_ONCE; @@ -55,9 +148,11 @@ bool event_poll(int32_t ms) uv_run(uv_default_loop(), run_mode); } while ( // Continue running if ... - !input_ready() // ... we have no input - && run_mode != UV_RUN_NOWAIT // ... ms != 0 - && !timed_out); // ... we didn't get a timeout + !input_ready() && // we have no input + !has_pending_events() && // no events are waiting to be processed + run_mode != UV_RUN_NOWAIT && // ms != 0 + !timed_out // we didn't get a timeout + ); input_stop(); @@ -66,7 +161,7 @@ bool event_poll(int32_t ms) uv_timer_stop(&timer); } - return input_ready(); + return input_ready() || has_pending_events(); } // Set a flag in the `event_poll` loop for signaling of a timeout |