From 6d17ed9f627958d392a5c2cd0b665786f37ceb21 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 11 Jul 2020 08:10:25 +0200 Subject: [PATCH] WIP: xcb_wait_for_special_event_with_timeout() This surely has portability problems and is ugly since it works with three different representations (timeout in milliseconds, deadline as timeval, deadline as timespec). Also, this is completely untested. But at least its a start. --- src/xcb.h | 7 +++++++ src/xcb_conn.c | 30 +++++++++++++++++++++++++++--- src/xcb_in.c | 37 +++++++++++++++++++++++++++++++++++++ src/xcbint.h | 1 + 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/xcb.h b/src/xcb.h index 09e123e..231986b 100644 --- a/src/xcb.h +++ b/src/xcb.h @@ -337,6 +337,13 @@ xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c, */ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c, xcb_special_event_t *se); + +/** + * @brief Returns the next event from a special queue, blocking until one arrives + */ +xcb_generic_event_t *xcb_wait_for_special_event_with_timeout(xcb_connection_t *c, + xcb_special_event_t *se, + unsigned int millisecs_timeout); /** * @typedef typedef struct xcb_extension_t xcb_extension_t */ diff --git a/src/xcb_conn.c b/src/xcb_conn.c index 8dab658..62002cb 100644 --- a/src/xcb_conn.c +++ b/src/xcb_conn.c @@ -37,6 +37,7 @@ #include #include #include +#include /* I bet this does not work on Windows... */ #include "xcb.h" #include "xcbint.h" @@ -434,6 +435,11 @@ xcb_connection_t *_xcb_conn_ret_error(int err) } int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count) +{ + return _xcb_conn_timedwait(c, cond, vector, count, NULL, NULL); +} + +int _xcb_conn_timedwait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count, struct timeval *now, struct timeval *deadline) { int ret; #if USE_POLL @@ -445,7 +451,13 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec /* If the thing I should be doing is already being done, wait for it. */ if(count ? c->out.writing : c->in.reading) { - pthread_cond_wait(cond, &c->iolock); + if(deadline) { + struct timespec spec; + spec.tv_sec = deadline->tv_sec; + spec.tv_nsec = deadline->tv_usec * 100; + pthread_cond_timedwait(cond, &c->iolock, &spec); + } else + pthread_cond_wait(cond, &c->iolock); return 1; } @@ -477,7 +489,13 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec pthread_mutex_unlock(&c->iolock); do { #if USE_POLL - ret = poll(&fd, 1, -1); + int timeout = -1; + if(deadline && now) { + struct timeval diff; + timersub(deadline, now, &diff); + timeout = now->tv_sec * 1000 + now->tv_usec / 1000; + } + ret = poll(&fd, 1, timeout); /* If poll() returns an event we didn't expect, such as POLLNVAL, treat * it as if it failed. */ if(ret >= 0 && (fd.revents & ~fd.events)) @@ -486,7 +504,13 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec break; } #else - ret = select(c->fd + 1, &rfds, &wfds, 0, 0); + struct timeval diff; + struct timeval *timeout = NULL; + if(deadline && now) { + timersub(deadline, now, &diff); + timeout = &diff; + } + ret = select(c->fd + 1, &rfds, &wfds, 0, timeout); #endif } while (ret == -1 && errno == EINTR); if(ret < 0) diff --git a/src/xcb_in.c b/src/xcb_in.c index 796b4e9..4018e0c 100644 --- a/src/xcb_in.c +++ b/src/xcb_in.c @@ -35,6 +35,7 @@ #include #include #include +#include /* I bet this does not work on Windows... */ #if USE_POLL #include @@ -778,6 +779,42 @@ xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c, return event; } +xcb_generic_event_t *xcb_wait_for_special_event_with_timeout(xcb_connection_t *c, + xcb_special_event_t *se, + unsigned int millisecs_timeout) +{ + struct timeval now, deadline, timeout; + special_list special; + xcb_generic_event_t *event; + + if(c->has_error) + return 0; + + timeout.tv_sec = millisecs_timeout / 1000; + timeout.tv_usec = (millisecs_timeout % 1000) * 1000; + gettimeofday(&now, NULL); // TODO: Check for errors? + timeradd(&now, &timeout, &deadline); + + pthread_mutex_lock(&c->iolock); + + insert_special(&c->in.special_waiters, &special, se); + + /* get_special_event returns 0 on empty list. */ + while(!(event = get_special_event(c, se))) { + if(timercmp(&deadline, &now, <)) + break; + if(!_xcb_conn_timedwait(c, &se->special_event_cond, 0, 0, &now, &deadline)) + break; + gettimeofday(&now, NULL); // TODO: Check for errors? + } + + remove_special(&c->in.special_waiters, &special); + + _xcb_in_wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + return event; +} + xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c, xcb_special_event_t *se) { diff --git a/src/xcbint.h b/src/xcbint.h index cef9821..0eda037 100644 --- a/src/xcbint.h +++ b/src/xcbint.h @@ -217,6 +217,7 @@ void _xcb_conn_shutdown(xcb_connection_t *c, int err); xcb_connection_t *_xcb_conn_ret_error(int err); int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count); +int _xcb_conn_timedwait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count, struct timeval *now, struct timeval *deadline); /* xcb_auth.c */