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