Reimplement the event queue in event.c using klist.h

- Add a new macro to klist.h: kl_empty()

   The whole point of abstract data structures is to avoid reimplementing
   common actions. The emptiness test seems to be such an action.

 - Add a new function attribute to func_attr.h: FUNC_ATTR_UNUSED

   Some of the many functions created by the macros in klist.h may end up not
   being used. Unused functions cause compilation errors as we compile with
   -Werror. To mark those functions as possibly unused we can use the
   FUNC_ATTR_UNUSED now.

 - Pass `Event` by value

   `Event` is such a small struct that I don't think we should allocate heap space
   and pass it by reference. Let's use the stack and memory cache in our favor
   passing it by value.
This commit is contained in:
Felipe Oliveira Carvalho 2014-04-05 23:37:39 -03:00 committed by Thiago de Arruda
parent fac85c1724
commit 967fb1aca6
6 changed files with 34 additions and 48 deletions

View File

@ -34,6 +34,7 @@
#define FUNC_ATTR_CONST __attribute__((const)) #define FUNC_ATTR_CONST __attribute__((const))
#define FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #define FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define FUNC_ATTR_ALWAYS_INLINE __attribute__((always_inline)) #define FUNC_ATTR_ALWAYS_INLINE __attribute__((always_inline))
#define FUNC_ATTR_UNUSED __attribute__((unused))
#ifdef __clang__ #ifdef __clang__
// clang only // clang only
@ -90,6 +91,10 @@
#define FUNC_ATTR_ALWAYS_INLINE #define FUNC_ATTR_ALWAYS_INLINE
#endif #endif
#ifndef FUNC_ATTR_UNUSED
#define FUNC_ATTR_UNUSED
#endif
#ifndef FUNC_ATTR_NONNULL_ALL #ifndef FUNC_ATTR_NONNULL_ALL
#define FUNC_ATTR_NONNULL_ALL #define FUNC_ATTR_NONNULL_ALL
#endif #endif

View File

@ -26,8 +26,10 @@
#ifndef _AC_KLIST_H #ifndef _AC_KLIST_H
#define _AC_KLIST_H #define _AC_KLIST_H
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include "func_attr.h"
#include "memory.h" #include "memory.h"
#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \ #define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \
@ -84,6 +86,8 @@
kl->head->next = 0; \ kl->head->next = 0; \
return kl; \ return kl; \
} \ } \
static inline void kl_destroy_##name(kl_##name##_t *kl) \
FUNC_ATTR_UNUSED; \
static inline void kl_destroy_##name(kl_##name##_t *kl) { \ static inline void kl_destroy_##name(kl_##name##_t *kl) { \
kl1_##name *p; \ kl1_##name *p; \
for (p = kl->head; p != kl->tail; p = p->next) \ for (p = kl->head; p != kl->tail; p = p->next) \
@ -119,5 +123,6 @@
#define kl_destroy(name, kl) kl_destroy_##name(kl) #define kl_destroy(name, kl) kl_destroy_##name(kl)
#define kl_pushp(name, kl) kl_pushp_##name(kl) #define kl_pushp(name, kl) kl_pushp_##name(kl)
#define kl_shift(name, kl, d) kl_shift_##name(kl, d) #define kl_shift(name, kl, d) kl_shift_##name(kl, d)
#define kl_empty(kl) ((kl)->size == 0)
#endif #endif

View File

@ -4,6 +4,7 @@
#include <uv.h> #include <uv.h>
#include "lib/klist.h"
#include "os/event.h" #include "os/event.h"
#include "os/input.h" #include "os/input.h"
#include "os/signal.h" #include "os/signal.h"
@ -11,22 +12,22 @@
#include "memory.h" #include "memory.h"
#include "misc2.h" #include "misc2.h"
typedef struct EventNode { // event.data will be cleaned up after the event is processed
Event *event; #define _destroy_event(x) // do nothing
struct EventNode *next; KLIST_INIT(Event, Event, _destroy_event)
} EventNode;
static EventNode *head, *tail; static klist_t(Event) *event_queue;
static uv_timer_t timer; static uv_timer_t timer;
static uv_prepare_t timer_prepare; static uv_prepare_t timer_prepare;
static bool poll_uv_loop(int ms); static bool poll_uv_loop(int ms);
static void process_all_events(void); static void process_all_events(void);
static bool has_pending_events(void);
static void timer_cb(uv_timer_t *handle, int); static void timer_cb(uv_timer_t *handle, int);
static void timer_prepare_cb(uv_prepare_t *, int); static void timer_prepare_cb(uv_prepare_t *, int);
void event_init() void event_init()
{ {
// Initialize the event queue
event_queue = kl_init(Event);
// Initialize input events // Initialize input events
input_init(); input_init();
// Timer to wake the event loop if a timeout argument is passed to // Timer to wake the event loop if a timeout argument is passed to
@ -72,50 +73,27 @@ bool event_poll(int32_t ms)
} }
// Push an event to the queue // Push an event to the queue
void event_push(Event *event) void event_push(Event event)
{ {
EventNode *node = (EventNode *)xmalloc(sizeof(EventNode)); *kl_pushp(Event, event_queue) = event;
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 // Runs the appropriate action for each queued event
static void process_all_events() static void process_all_events()
{ {
EventNode *next; Event event;
Event *event;
while (has_pending_events()) { while (kl_shift(Event, event_queue, &event) == 0) {
next = head->next; switch (event.type) {
event = head->event;
free(head);
head = next;
switch (event->type) {
case kEventSignal: case kEventSignal:
signal_handle(event); signal_handle(event);
break; break;
default: default:
abort(); abort();
} }
} }
} }
// Checks if there are queued events
bool has_pending_events()
{
return head != NULL;
}
// Wait for some event // Wait for some event
static bool poll_uv_loop(int32_t ms) static bool poll_uv_loop(int32_t ms)
{ {
@ -150,7 +128,7 @@ static bool poll_uv_loop(int32_t ms)
} while ( } while (
// Continue running if ... // Continue running if ...
!input_ready() && // we have no input !input_ready() && // we have no input
!has_pending_events() && // 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 !timed_out // we didn't get a timeout
); );
@ -162,7 +140,7 @@ static bool poll_uv_loop(int32_t ms)
uv_timer_stop(&timer); uv_timer_stop(&timer);
} }
return input_ready() || has_pending_events(); return input_ready() || !kl_empty(event_queue);
} }
// 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

View File

@ -15,7 +15,7 @@ typedef struct {
void event_init(void); void event_init(void);
bool event_poll(int32_t ms); bool event_poll(int32_t ms);
void event_push(Event *event); void event_push(Event event);
#endif // NEOVIM_OS_EVENT_H #endif // NEOVIM_OS_EVENT_H

View File

@ -67,12 +67,11 @@ void signal_accept_deadly()
rejecting_deadly = false; rejecting_deadly = false;
} }
void signal_handle(Event *event) void signal_handle(Event event)
{ {
int signum = *(int *)event->data; int signum = *(int *)event.data;
free(event->data); free(event.data);
free(event);
switch (signum) { switch (signum) {
case SIGINT: case SIGINT:
@ -148,8 +147,6 @@ static void deadly_signal(int signum)
static void signal_cb(uv_signal_t *handle, int signum) static void signal_cb(uv_signal_t *handle, int signum)
{ {
Event *event;
if (rejecting_deadly) { if (rejecting_deadly) {
if (signum == SIGINT) { if (signum == SIGINT) {
got_int = true; got_int = true;
@ -158,9 +155,10 @@ static void signal_cb(uv_signal_t *handle, int signum)
return; return;
} }
event = (Event *)xmalloc(sizeof(Event)); Event event = {
event->type = kEventSignal; .type = kEventSignal,
event->data = xmalloc(sizeof(int)); .data = xmalloc(sizeof(int))
*(int *)event->data = signum; };
*(int *)event.data = signum;
event_push(event); event_push(event);
} }

View File

@ -7,7 +7,7 @@ void signal_init(void);
void signal_stop(void); void signal_stop(void);
void signal_accept_deadly(void); void signal_accept_deadly(void);
void signal_reject_deadly(void); void signal_reject_deadly(void);
void signal_handle(Event *event); void signal_handle(Event event);
#endif #endif