[Xcb] [Patch] Fix busy-loop on BSD

Josh Triplett josh at joshtriplett.org
Thu Mar 8 01:57:25 PST 2012


On Thu, Mar 08, 2012 at 10:21:15AM +0100, Uli Schlachter wrote:
> From 9854c4591df6d96b79cc055a8020b5eda8ad1a56 Mon Sep 17 00:00:00 2001
> From: Uli Schlachter <psychon at znc.in>
> Date: Thu, 1 Mar 2012 20:26:39 +0100
> Subject: [PATCH] Fix a busy loop on BSD and Mac OS
> 
> On FreeBSD MSG_WAITALL on a non-blocking socket fails immediately if less bytes
> than were asked for are available. This is different than the behavior on linux
> where as many bytes as are available are returned in this case. Other OS
> apparently follow the FreeBSD behavior.
> 
> _xcb_in_read() is used to fill xcb's read buffer, thus this function will call
> recv() with a big length argument (xcb's read buffer is by default 16 KiB
> large). That many bytes are highly unlikely to be available in the kernel
> buffer.
> 
> This means that _xcb_in_read() always failed on FreeBSD. Since the socket was
> still signaled as readable by poll(), this bug even resulted in a busy loop.
> 
> The same issue is present in read_block(), but here it is slightly different.
> read_block() is called when we read the first few bytes of an event or a reply,
> so that we already know its length. This means that we should be able to use
> MSG_WAITALL here, because we know how many bytes there have to be.
> 
> However, that function could busy loop, too, when only the first few bytes of
> the packet were sent while the rest is stuck somewhere on the way to us. Thus,
> MSG_WAITALL should be removed here, too.
> 
> Thanks to Christoph Egger from Debian for noticing the problem, doing all the
> necessary debugging and figuring out what the problem was! This patch is 99%
> from debian. Thanks for all the work.
> 
> This bug was introduced in commit 2dcf8b025be88a25d4333abdc28d425b88238d96.
> 
> This commit also reverts commit 9061ee45b8dbe5431c23e3f628089d703ccad0b1.
> 
> Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=45776
> 
> Signed-off-by: Uli Schlachter <psychon at znc.in>

Reviewed-by: Josh Triplett <josh at joshtriplett.org>

>  src/xcb_in.c |   17 ++---------------
>  1 files changed, 2 insertions(+), 15 deletions(-)
> 
> diff --git a/src/xcb_in.c b/src/xcb_in.c
> index fdcc813..4998cdd 100644
> --- a/src/xcb_in.c
> +++ b/src/xcb_in.c
> @@ -51,11 +51,6 @@
>  #define XCB_REPLY 1
>  #define XCB_XGE_EVENT 35
>  
> -/* required for compiling for Win32 using MinGW */
> -#ifndef MSG_WAITALL
> -#define MSG_WAITALL 0
> -#endif
> -
>  struct event_list {
>      xcb_generic_event_t *event;
>      struct event_list *next;
> @@ -269,11 +264,7 @@ static int read_block(const int fd, void *buf, const ssize_t len)
>      int done = 0;
>      while(done < len)
>      {
> -#ifdef __APPLE__
> -        int ret = read(fd, ((char *) buf) + done, len - done);
> -#else
> -        int ret = recv(fd, ((char *) buf) + done, len - done,MSG_WAITALL);
> -#endif
> +        int ret = recv(fd, ((char *) buf) + done, len - done, 0);
>          if(ret > 0)
>              done += ret;
>  #ifndef _WIN32
> @@ -665,11 +656,7 @@ void _xcb_in_replies_done(xcb_connection_t *c)
>  
>  int _xcb_in_read(xcb_connection_t *c)
>  {
> -#ifdef __APPLE__
> -    int n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
> -#else
> -    int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len,MSG_WAITALL);
> -#endif
> +    int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
>      if(n > 0)
>          c->in.queue_len += n;
>      while(read_packet(c))


More information about the Xcb mailing list