Switch to a state machine to handle incomplete syncs

A caller may start syncing but switch back to normal half-way through the
sync. In that case, we need to drop all sync events and continue with
regular events only.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2013-07-02 10:50:37 +10:00
parent f3a6b0c685
commit c661e80ba0
2 changed files with 39 additions and 11 deletions

View file

@ -51,6 +51,23 @@
_a > _b ? _a : _b; \ _a > _b ? _a : _b; \
}) })
/**
* Sync state machine:
* default state: SYNC_NONE
*
* SYNC_NONE SYN_DROPPED or forced sync SYNC_NEEDED
* SYNC_NEEDED libevdev_next_event(LIBEVDEV_READ_SYNC) SYNC_IN_PROGRESS
* SYNC_NEEDED libevdev_next_event(LIBEVDEV_READ_SYNC_NONE) SYNC_NONE
* SYNC_IN_PROGRESS libevdev_next_event(LIBEVDEV_READ_SYNC_NONE) SYNC_NONE
* SYNC_IN_PROGRESS no sync events left SYNC_NONE
*
*/
enum SyncState {
SYNC_NONE,
SYNC_NEEDED,
SYNC_IN_PROGRESS,
};
struct libevdev { struct libevdev {
int fd; int fd;
libevdev_log_func_t log; libevdev_log_func_t log;
@ -78,7 +95,7 @@ struct libevdev {
int current_slot; int current_slot;
int rep_values[2]; int rep_values[2];
int need_sync; enum SyncState sync_state;
int grabbed; int grabbed;
struct input_event *queue; struct input_event *queue;

View file

@ -74,6 +74,7 @@ libevdev_new(void)
dev->current_slot = -1; dev->current_slot = -1;
dev->log = libevdev_noop_log_func; dev->log = libevdev_noop_log_func;
dev->grabbed = LIBEVDEV_UNGRAB; dev->grabbed = LIBEVDEV_UNGRAB;
dev->sync_state = SYNC_NONE;
return dev; return dev;
} }
@ -401,7 +402,7 @@ sync_state(struct libevdev *dev)
/* FIXME: if we have events in the queue after the SYN_DROPPED (which was /* FIXME: if we have events in the queue after the SYN_DROPPED (which was
queue[0]) we need to shift this backwards. Except that chances are that the queue[0]) we need to shift this backwards. Except that chances are that the
queue may be either full or too full to prepend all the events needed for queue may be either full or too full to prepend all the events needed for
syncing. SYNC_IN_PROGRESS.
so we search for the last sync event in the queue and drop everything before so we search for the last sync event in the queue and drop everything before
including that event and rely on the kernel to tell us the right value for that including that event and rely on the kernel to tell us the right value for that
@ -429,7 +430,6 @@ sync_state(struct libevdev *dev)
init_event(dev, ev, EV_SYN, SYN_REPORT, 0); init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
dev->queue_nsync = queue_num_elements(dev); dev->queue_nsync = queue_num_elements(dev);
dev->need_sync = 0;
return rc; return rc;
} }
@ -540,23 +540,32 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
return -EINVAL; return -EINVAL;
if (flags & LIBEVDEV_READ_SYNC) { if (flags & LIBEVDEV_READ_SYNC) {
if (!dev->need_sync && dev->queue_nsync == 0) if (dev->sync_state == SYNC_NEEDED) {
return -EAGAIN;
else if (dev->need_sync) {
rc = sync_state(dev); rc = sync_state(dev);
if (rc != 0) if (rc != 0)
return rc; return rc;
dev->sync_state = SYNC_IN_PROGRESS;
} }
} else if (dev->need_sync) {
if (dev->queue_nsync == 0) {
dev->sync_state = SYNC_NONE;
return -EAGAIN;
}
} else if (dev->sync_state != SYNC_NONE) {
struct input_event e; struct input_event e;
/* call update_state for all events here, otherwise the library has the wrong view /* call update_state for all events here, otherwise the library has the wrong view
of the device too */ of the device too */
while (queue_shift(dev, &e) == 0) while (queue_shift(dev, &e) == 0) {
dev->queue_nsync--;
update_state(dev, &e); update_state(dev, &e);
}
dev->sync_state = SYNC_NONE;
} }
/* FIXME: if the first event after syncing is a SYN_DROPPED, log this */ /* FIXME: if the first event after SYNC_IN_PROGRESS is a SYN_DROPPED, log this */
/* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED, /* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED,
worst case we don't read fast enough and end up with SYN_DROPPED anyway. worst case we don't read fast enough and end up with SYN_DROPPED anyway.
@ -573,7 +582,7 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
} }
if (flags & LIBEVDEV_FORCE_SYNC) { if (flags & LIBEVDEV_FORCE_SYNC) {
dev->need_sync = 1; dev->sync_state = SYNC_NEEDED;
rc = 1; rc = 1;
goto out; goto out;
} }
@ -589,13 +598,15 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
rc = 0; rc = 0;
if (ev->type == EV_SYN && ev->code == SYN_DROPPED) { if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
dev->need_sync = 1; dev->sync_state = SYNC_NEEDED;
rc = 1; rc = 1;
} }
if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) { if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) {
dev->queue_nsync--; dev->queue_nsync--;
rc = 1; rc = 1;
if (dev->queue_nsync == 0)
dev->sync_state = SYNC_NONE;
} }
out: out: