From 342a43e7b2ceec1dd200bffa24b052fec33f5bdc Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 30 Jul 2010 15:29:38 +0200 Subject: Introduce threading In order to enable deferred events from grail, but the event processing in a separate thread, and have the calling thread return as quickly as possible. Signed-off-by: Henrik Rydberg --- src/grail-api.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) (limited to 'src/grail-api.c') diff --git a/src/grail-api.c b/src/grail-api.c index 19b66aa..e3b8125 100644 --- a/src/grail-api.c +++ b/src/grail-api.c @@ -1,6 +1,8 @@ #include "grail-inserter.h" #include "grail-recognizer.h" #include +#include +#include #include #include #include @@ -9,12 +11,48 @@ #include #include "evbuf.h" +static const pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER; +static const pthread_cond_t c_wait = PTHREAD_COND_INITIALIZER; + struct grail_impl { struct touch_dev dev; struct touch_engine engine; struct evbuf evbuf; + int fd; + int pull, finished; + pthread_mutex_t mutex; + pthread_cond_t wait; + pthread_t thread; }; +/* + * While not finished, lock, wait for condition, extract the running + * state, unlock, then process the event queue. + * + * The processing may in principle take seconds to complete without + * locking up the writer side. + */ +static void *grail_thread(void *priv) +{ + struct grail_impl *x = priv; + int pull, finished = 0; + sigset_t block; + sigemptyset(&block); + sigaddset(&block, SIGIO); + pthread_sigmask(SIG_BLOCK, &block, NULL); + while (!finished) { + pthread_mutex_lock(&x->mutex); + pthread_cond_wait(&x->wait, &x->mutex); + pull = x->pull; + finished = x->finished; + x->pull = 0; + pthread_mutex_unlock(&x->mutex); + if (!finished && pull) + touch_dev_process(&x->dev); + } + pthread_exit(NULL); +} + static void tp_event(struct touch_engine *engine, const struct input_event *ev) { @@ -66,10 +104,18 @@ int grail_open(struct grail *ge, int fd) ret = touch_dev_open(&x->dev, fd); if (ret) goto freegru; + x->fd = fd; + x->mutex = c_mutex; + x->wait = c_wait; + ret = pthread_create(&x->thread, NULL, grail_thread, x); + if (ret) + goto freetouch; + ge->impl = x; touch_engine_init(&x->engine, tp_event, tp_sync, ge); touch_engine_attach(&x->engine, &x->dev); - ge->impl = x; return 0; + freetouch: + touch_dev_close(&x->dev, fd); freegru: gru_destroy(ge); freedev: @@ -82,6 +128,11 @@ int grail_open(struct grail *ge, int fd) void grail_close(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; + void *status; + pthread_mutex_lock(&x->mutex); + x->finished = 1; + pthread_cond_signal (&x->wait); + pthread_mutex_unlock(&x->mutex); touch_engine_detach(&x->engine, &x->dev); touch_dev_close(&x->dev, fd); gru_destroy(ge); @@ -93,12 +144,28 @@ void grail_close(struct grail *ge, int fd) int grail_idle(struct grail *ge, int fd, int ms) { struct grail_impl *x = ge->impl; - return touch_dev_idle(&x->dev, fd, ms); + int ret; + pthread_mutex_lock(&x->mutex); + ret = touch_dev_idle(&x->dev, fd, ms); + pthread_mutex_unlock(&x->mutex); + return ret; } +/* + * First extract all input events to a lockless circular buffer, then, + * under lock, signal the worker thread. + * + * This function only blocks temporarily while signalling the worker + * thread. + */ int grail_pull(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; - return touch_dev_pull(&x->dev, fd); + int finished = touch_dev_fetch(&x->dev, fd) < 0; + pthread_mutex_lock(&x->mutex); + x->pull = 1; + x->finished = finished; + pthread_cond_signal(&x->wait); + pthread_mutex_unlock(&x->mutex); + return 1; } - -- cgit v1.2.3