From 549f0f0bcd3ceec21393e953e13a86a716fc9580 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 30 May 2013 11:05:24 +1000 Subject: [PATCH] Abstract the event queue away Provide a couple of handler functions to avoid erroneous queue updates. This will make it easier if we need to swap queue implementation later. Signed-off-by: Peter Hutterer --- libevdev/libevdev-int.h | 99 +++++++++++++++++++++++++++++++++++++++++ libevdev/libevdev.c | 46 ++++++++----------- 2 files changed, 117 insertions(+), 28 deletions(-) diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h index d287697..848c1a5 100644 --- a/libevdev/libevdev-int.h +++ b/libevdev/libevdev-int.h @@ -61,5 +61,104 @@ struct libevdev { size_t queue_nsync; /**< number of sync events */ }; +/** + * @return a pointer to the next element in the queue, or NULL if the queue + * is full. + */ +static inline struct input_event* +queue_push(struct libevdev *dev) +{ + if (dev->queue_next >= dev->queue_size) + return NULL; + + return &dev->queue[dev->queue_next++]; +} + +/** + * Set ev to the last element in the queue, removing it from the queue. + * + * @return 0 on success, 1 if the queue is empty. + */ +static inline int +queue_pop(struct libevdev *dev, struct input_event *ev) +{ + if (dev->queue_next == 0) + return 1; + + *ev = dev->queue[--dev->queue_next]; + + return 0; +} + +/** + * Set ev to the first element in the queue, shifting everything else + * forward by one. + * + * @return 0 on success, 1 if the queue is empty. + */ +static inline int +queue_shift(struct libevdev *dev, struct input_event *ev) +{ + int i; + + if (dev->queue_next == 0) + return 1; + + *ev = dev->queue[0]; + + for (i = 0; i < dev->queue_next - 1; i++) + dev->queue[i] = dev->queue[i + 1]; + + dev->queue_next--; + + return 0; +} + +static inline int +queue_alloc(struct libevdev *dev, int size) +{ + dev->queue = calloc(size, sizeof(struct input_event)); + if (!dev->queue) + return -ENOSPC; + + dev->queue_size = size; + dev->queue_next = 0; + return 0; +} + +static inline int +queue_num_elements(struct libevdev *dev) +{ + return dev->queue_next; +} + +static inline int +queue_size(struct libevdev *dev) +{ + return dev->queue_size; +} + +static inline int +queue_num_free_elements(struct libevdev *dev) +{ + return dev->queue_size - dev->queue_next - 1; +} + +static inline struct input_event * +queue_next_element(struct libevdev *dev) +{ + return &dev->queue[dev->queue_next]; +} + +static inline int +queue_set_num_elements(struct libevdev *dev, int nelem) +{ + if (nelem > dev->queue_size) + return 1; + + dev->queue_next = nelem; + + return 0; +} #endif diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index 11b3492..561d0c5 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -125,14 +125,7 @@ init_event_queue(struct libevdev *dev) const int QUEUE_SIZE = 256; - dev->queue = calloc(QUEUE_SIZE, sizeof(struct input_event)); - if (!dev->queue) - return -ENOSPC; - - dev->queue_size = QUEUE_SIZE; - dev->queue_next = 0; - - return 0; + return queue_alloc(dev, QUEUE_SIZE); } static void @@ -293,12 +286,13 @@ sync_key_state(struct libevdev *dev) goto out; for (i = 0; i < KEY_MAX; i++) { - struct input_event *ev = &dev->queue[dev->queue_next++]; int old, new; old = bit_is_set(dev->key_values, i); new = bit_is_set(keystate, i); - if (old ^ new) + if (old ^ new) { + struct input_event *ev = queue_push(dev); init_event(ev, EV_KEY, i, new ? 1 : 0); + } set_bit_state(dev->key_values, i, new); } @@ -327,7 +321,7 @@ sync_abs_state(struct libevdev *dev) goto out; if (dev->abs_info[i].value != abs_info.value) { - struct input_event *ev = &dev->queue[dev->queue_next++]; + struct input_event *ev = queue_push(dev); init_event(ev, EV_ABS, i, abs_info.value); dev->abs_info[i].value = abs_info.value; @@ -365,7 +359,7 @@ sync_mt_state(struct libevdev *dev) int j; struct input_event *ev; - ev = &dev->queue[dev->queue_next++]; + ev = queue_push(dev); init_event(ev, EV_ABS, ABS_MT_SLOT, i); for (j = ABS_MT_MIN; j < ABS_MT_MAX; j++) { int jdx = j - ABS_MT_MIN; @@ -373,7 +367,7 @@ sync_mt_state(struct libevdev *dev) if (dev->mt_slot_vals[i][jdx] == mt_state[jdx].val[i]) continue; - ev = &dev->queue[dev->queue_next++]; + ev = queue_push(dev); init_event(ev, EV_ABS, j, mt_state[jdx].val[i]); dev->mt_slot_vals[i][jdx] = mt_state[jdx].val[i]; } @@ -401,10 +395,10 @@ sync_state(struct libevdev *dev) if (rc == 0 && libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) rc = sync_mt_state(dev); - ev = &dev->queue[dev->queue_next++]; + ev = queue_push(dev); init_event(ev, EV_SYN, SYN_REPORT, 0); - dev->queue_nsync = dev->queue_next; + dev->queue_nsync = queue_num_elements(dev); dev->need_sync = 0; return rc; @@ -466,18 +460,22 @@ read_more_events(struct libevdev *dev) { int free_elem; int len; + struct input_event *next; - free_elem = dev->queue_size - dev->queue_next - 1; + free_elem = queue_num_free_elements(dev); if (free_elem <= 0) return 0; - len = read(dev->fd, &dev->queue[dev->queue_next], free_elem * sizeof(struct input_event)); + next = queue_next_element(dev); + len = read(dev->fd, next, free_elem * sizeof(struct input_event)); if (len < 0) { return -errno; } else if (len > 0 && len % sizeof(struct input_event) != 0) return -EINVAL; - else if (len > 0) - dev->queue_next += len/sizeof(struct input_event); + else if (len > 0) { + int nev = len/sizeof(struct input_event); + queue_set_num_elements(dev, queue_num_elements(dev) + nev); + } return 0; } @@ -485,7 +483,6 @@ read_more_events(struct libevdev *dev) int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev) { int rc = 0; - int i; if (dev->fd < 0) return -ENODEV; @@ -509,11 +506,9 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e if (rc < 0 && rc != -EAGAIN) goto out; - if (dev->queue_next == 0) + if (queue_shift(dev, ev) != 0) return -EAGAIN; - *ev = dev->queue[0]; - update_state(dev, ev); rc = 0; @@ -522,11 +517,6 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e rc = 1; } - for (i = 0; dev->queue_next > 1 && i < dev->queue_next - 1; i++) - dev->queue[i] = dev->queue[i + 1]; - - dev->queue_next--; - if (flags & ER_SYNC && dev->queue_nsync > 0) { dev->queue_nsync--; rc = 1;