events: Refactor event_poll to use stack-allocated timer handles

This commit is contained in:
Thiago de Arruda
2014-06-17 12:27:02 -03:00
parent 4cb5ce3c52
commit 05bf7808e0

View File

@@ -21,12 +21,16 @@
#define _destroy_event(x) // do nothing #define _destroy_event(x) // do nothing
KLIST_INIT(Event, Event, _destroy_event) KLIST_INIT(Event, Event, _destroy_event)
typedef struct {
bool timed_out;
int32_t ms;
uv_timer_t *timer;
} TimerData;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/event.c.generated.h" # include "os/event.c.generated.h"
#endif #endif
static klist_t(Event) *event_queue; static klist_t(Event) *event_queue;
static uv_timer_t timer;
static uv_prepare_t timer_prepare;
void event_init() void event_init()
{ {
@@ -44,9 +48,6 @@ void event_init()
channel_init(); channel_init();
// Servers // Servers
server_init(); 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() void event_teardown()
@@ -59,7 +60,6 @@ void event_teardown()
// Wait for some event // Wait for some event
bool event_poll(int32_t ms) bool event_poll(int32_t ms)
{ {
bool timed_out;
uv_run_mode run_mode = UV_RUN_ONCE; uv_run_mode run_mode = UV_RUN_ONCE;
if (input_ready()) { if (input_ready()) {
@@ -68,14 +68,20 @@ bool event_poll(int32_t ms)
} }
input_start(); input_start();
timed_out = false;
uv_timer_t timer;
uv_prepare_t timer_prepare;
TimerData timer_data = {.ms = ms, .timed_out = false, .timer = &timer};
if (ms > 0) { 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 // 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 // We only start the timer after the loop is running, for that we
// use a prepare handle(pass the interval as data to it) // 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); uv_prepare_start(&timer_prepare, timer_prepare_cb);
} else if (ms == 0) { } else if (ms == 0) {
// For ms == 0, we need to do a non-blocking event poll by // For ms == 0, we need to do a non-blocking event poll by
@@ -92,13 +98,17 @@ bool event_poll(int32_t ms)
!input_ready() && // we have no input !input_ready() && // we have no input
kl_empty(event_queue) && // no events are waiting to be processed kl_empty(event_queue) && // no events are waiting to be processed
run_mode != UV_RUN_NOWAIT && // ms != 0 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(); input_stop();
if (ms > 0) { if (ms > 0) {
// Stop the timer // Ensure the timer-related handles are closed and run the event loop
uv_timer_stop(&timer); // 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_is_pending();
@@ -140,11 +150,14 @@ void event_process()
// Set a flag in the `event_poll` loop for signaling of a timeout // Set a flag in the `event_poll` loop for signaling of a timeout
static void timer_cb(uv_timer_t *handle) 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) static void timer_prepare_cb(uv_prepare_t *handle)
{ {
uv_timer_start(&timer, timer_cb, *(uint32_t *)timer_prepare.data, 0); TimerData *data = handle->data;
uv_prepare_stop(&timer_prepare); assert(data->ms > 0);
uv_timer_start(data->timer, timer_cb, (uint32_t)data->ms, 0);
uv_prepare_stop(handle);
} }