diff --git a/src/xcb.h b/src/xcb.h index 59c779d..34df069 100644 --- a/src/xcb.h +++ b/src/xcb.h @@ -361,6 +361,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 8f91f43..3e75f85 100644 --- a/src/xcb_conn.c +++ b/src/xcb_conn.c @@ -36,6 +36,7 @@ #include #include #include +#include /* I bet this does not work on Windows... */ #include "xcb.h" #include "xcbint.h" @@ -464,6 +465,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 @@ -475,7 +481,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; } @@ -507,7 +519,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)) @@ -516,7 +534,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 c9a264d..3056848 100644 --- a/src/xcb_in.c +++ b/src/xcb_in.c @@ -34,6 +34,7 @@ #include #include #include +#include /* I bet this does not work on Windows... */ #if USE_POLL #include @@ -789,6 +790,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 9836def..29ac373 100644 --- a/src/xcbint.h +++ b/src/xcbint.h @@ -229,6 +229,7 @@ XCB_CONST_FUNCTION 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 */