diff options
Diffstat (limited to 'src/os/event.c')
-rw-r--r-- | src/os/event.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/os/event.c b/src/os/event.c new file mode 100644 index 0000000000..1abde8d075 --- /dev/null +++ b/src/os/event.c @@ -0,0 +1,74 @@ +#include <stdint.h> +#include <stdbool.h> + +#include <uv.h> + +#include "os/event.h" +#include "os/input.h" + +static uv_timer_t timer_req; +static void timer_cb(uv_timer_t *handle, int); + +void event_init() +{ + /* Initialize input events */ + input_init(); + /* Timer to wake the event loop if a timeout argument is passed to + * `event_poll` */ + uv_timer_init(uv_default_loop(), &timer_req); +} + +/* Wait for some event */ +EventType event_poll(int32_t ms) +{ + bool timed_out; + EventType event; + uv_run_mode run_mode = UV_RUN_ONCE; + + if ((event = input_check()) != kEventNone) { + /* If there's a pending input event to be consumed, do it now */ + return event; + } + + input_start(); + timed_out = false; + + if (ms > 0) { + /* Timeout passed as argument, start the libuv timer to wake us up and + * set our local flag */ + timer_req.data = &timed_out; + uv_timer_start(&timer_req, timer_cb, ms, 0); + } else if (ms == 0) { + /* + * For ms == 0, we need to do a non-blocking event poll by + * setting the run mode to UV_RUN_NOWAIT. + */ + run_mode = UV_RUN_NOWAIT; + } + + do { + /* Wait for some event */ + uv_run(uv_default_loop(), run_mode); + } while ( + /* Continue running if ... */ + (event = input_check()) == kEventNone && /* ... we have no input */ + run_mode != UV_RUN_NOWAIT && /* ... ms != 0 */ + !timed_out /* ... we didn't get a timeout */ + ); + + input_stop(); + + if (!timed_out && ms > 0) { + /* Timer event did not trigger, stop the watcher since we no longer + * care about it */ + uv_timer_stop(&timer_req); + } + + return event; +} + +/* Set a flag in the `event_poll` loop for signaling of a timeout */ +static void timer_cb(uv_timer_t *handle, int status) +{ + *((bool *)handle->data) = true; +} |