Merge branch 'flush-immediately' into 'master'

Introduce xcb_flush_nonblock()

See merge request xorg/lib/libxcb!82
This commit is contained in:
Simon Ser 2026-05-13 11:54:14 +00:00
commit 05c3c6eedf
5 changed files with 58 additions and 30 deletions

View file

@ -269,6 +269,16 @@ typedef struct xcb_auth_info_t {
*/
int xcb_flush(xcb_connection_t *c);
/**
* @brief Forces any buffered output to be written to the server without blocking.
* @param c The connection to the X server.
* @return > @c 0 on success, <= @c 0 otherwise.
*
* Forces any buffered output to be written to the server. Does not block,
* returns immediately with errno set to EAGAIN if the write would block.
*/
int xcb_flush_nonblock(xcb_connection_t *c);
/**
* @brief Returns the maximum request length that this server accepts.
* @param c The connection to the X server.

View file

@ -163,7 +163,7 @@ static int write_setup(xcb_connection_t *c, xcb_auth_info_t *auth_info)
assert(count <= (int) (sizeof(parts) / sizeof(*parts)));
pthread_mutex_lock(&c->iolock);
ret = _xcb_out_send(c, parts, count);
ret = _xcb_out_send(c, parts, count, 1);
pthread_mutex_unlock(&c->iolock);
return ret;
}
@ -463,13 +463,14 @@ 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_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count, int timeout)
{
int ret;
#if USE_POLL
struct pollfd fd;
#else
fd_set rfds, wfds;
struct timeval timeout_timeval;
#endif
/* If the thing I should be doing is already being done, wait for it. */
@ -507,7 +508,7 @@ 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);
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 +517,9 @@ 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);
timeout_timeval.tv_sec = timeout / 1000;
timeout_timeval.tv_usec = (timeout % 1000) * 1000;
ret = select(c->fd + 1, &rfds, &wfds, 0, timeout >= 0 ? &timeout_timeval : 0);
#endif
} while (ret == -1 && errno == EINTR);
if(ret < 0)

View file

@ -511,7 +511,7 @@ static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_e
void *ret = 0;
/* If this request has not been written yet, write it. */
if(c->out.return_socket || _xcb_out_flush_to(c, request))
if(c->out.return_socket || _xcb_out_flush_to(c, request, 1))
{
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
reader_list reader;
@ -519,7 +519,7 @@ static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_e
insert_reader(&c->in.readers, &reader, request, &cond);
while(!poll_for_reply(c, request, &ret, e))
if(!_xcb_conn_wait(c, &cond, 0, 0))
if(!_xcb_conn_wait(c, &cond, 0, 0, -1))
break;
remove_reader(&c->in.readers, &reader);
@ -700,7 +700,7 @@ xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c)
pthread_mutex_lock(&c->iolock);
/* get_event returns 0 on empty list. */
while(!(ret = get_event(c)))
if(!_xcb_conn_wait(c, &c->in.event_cond, 0, 0))
if(!_xcb_conn_wait(c, &c->in.event_cond, 0, 0, -1))
break;
_xcb_in_wake_up_next_reader(c);
@ -750,7 +750,7 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
}
if (XCB_SEQUENCE_COMPARE(request, >=, c->out.request_expected_written))
{
_xcb_out_flush_to(c, c->out.request);
_xcb_out_flush_to(c, c->out.request, 1);
}
}
reply = wait_for_reply(c, request, &ret);
@ -803,7 +803,7 @@ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
/* get_special_event returns 0 on empty list. */
while(!(event = get_special_event(c, se)))
if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0))
if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0, -1))
break;
remove_special(&c->in.special_waiters, &special);

View file

@ -30,6 +30,7 @@
#endif
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
@ -69,7 +70,7 @@ static inline void send_request(xcb_connection_t *c, int isvoid, enum workaround
vector[0].iov_base = c->out.queue;
vector[0].iov_len = c->out.queue_len;
c->out.queue_len = 0;
_xcb_out_send(c, vector, count);
_xcb_out_send(c, vector, count, 1);
}
static void send_sync(xcb_connection_t *c)
@ -204,7 +205,7 @@ static void send_fds(xcb_connection_t *c, int *fds, unsigned int num_fds)
/* XXX: if c->out.writing > 0, this releases the iolock and
* potentially allows other threads to interfere with their own fds.
*/
_xcb_out_flush_to(c, c->out.request);
_xcb_out_flush_to(c, c->out.request, 1);
if (c->out.out_fd.nfd == XCB_MAX_PASS_FD) {
/* We need some request to send FDs with */
@ -385,7 +386,7 @@ int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), v
* write requests, so keep flushing until we're done
*/
do
ret = _xcb_out_flush_to(c, c->out.request);
ret = _xcb_out_flush_to(c, c->out.request, 1);
while (ret && c->out.request != c->out.request_written);
if(ret)
{
@ -413,20 +414,30 @@ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t re
return 0;
pthread_mutex_lock(&c->iolock);
c->out.request += requests;
ret = _xcb_out_send(c, vector, count);
ret = _xcb_out_send(c, vector, count, 1);
pthread_mutex_unlock(&c->iolock);
return ret;
}
static int flush(xcb_connection_t *c, int block)
{
int ret;
if(c->has_error)
return 0;
pthread_mutex_lock(&c->iolock);
ret = _xcb_out_flush_to(c, c->out.request, block);
pthread_mutex_unlock(&c->iolock);
return ret;
}
int xcb_flush(xcb_connection_t *c)
{
int ret;
if(c->has_error)
return 0;
pthread_mutex_lock(&c->iolock);
ret = _xcb_out_flush_to(c, c->out.request);
pthread_mutex_unlock(&c->iolock);
return ret;
return flush(c, 1);
}
int xcb_flush_nonblock(xcb_connection_t *c)
{
return flush(c, 0);
}
/* Private interface */
@ -463,13 +474,17 @@ void _xcb_out_destroy(_xcb_out *out)
pthread_cond_destroy(&out->socket_cond);
}
int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count)
int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count, int block)
{
int timeout = block ? -1 : 0;
int ret = 1;
while(ret && count)
ret = _xcb_conn_wait(c, &c->out.cond, &vector, &count);
c->out.request_written = c->out.request;
c->out.request_expected_written = c->in.request_expected;
errno = 0;
while(ret && count && errno != EAGAIN)
ret = _xcb_conn_wait(c, &c->out.cond, &vector, &count, timeout);
if (count == 0) {
c->out.request_written = c->out.request;
c->out.request_expected_written = c->in.request_expected;
}
pthread_cond_broadcast(&c->out.cond);
_xcb_in_wake_up_next_reader(c);
return ret;
@ -481,7 +496,7 @@ void _xcb_out_send_sync(xcb_connection_t *c)
send_sync(c);
}
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request, int block)
{
assert(XCB_SEQUENCE_COMPARE(request, <=, c->out.request));
if(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request))
@ -492,7 +507,7 @@ int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
vec.iov_base = c->out.queue;
vec.iov_len = c->out.queue_len;
c->out.queue_len = 0;
return _xcb_out_send(c, &vec, 1);
return _xcb_out_send(c, &vec, 1, block);
}
while(c->out.writing)
pthread_cond_wait(&c->out.cond, &c->iolock);

View file

@ -128,9 +128,9 @@ typedef struct _xcb_out {
int _xcb_out_init(_xcb_out *out);
void _xcb_out_destroy(_xcb_out *out);
int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count);
int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count, int timeout);
void _xcb_out_send_sync(xcb_connection_t *c);
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request);
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request, int timeout);
/* xcb_in.c */
@ -226,7 +226,7 @@ void _xcb_conn_shutdown(xcb_connection_t *c, int err);
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_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count, int timeout);
/* xcb_auth.c */