[PATCH] Fix a busy loop on BSD and Mac OS

Uli Schlachter psychon at znc.in
Thu Mar 1 11:26:39 PST 2012


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>
---
 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))
-- 
1.7.9.1


--------------050607050908020402050502--


More information about the Xcb mailing list