Cannot wait for user lock in sync_while_locked

Submitted by Keith Packard on March 3, 2012, 10:08 a.m.

Details

Message ID 1330769283-32223-1-git-send-email-keithp@keithp.com
State Superseded
Headers show

Not browsing as part of any series.

Commit Message

Keith Packard March 3, 2012, 10:08 a.m.
sync_while_locked grabs the user lock before performing the sync
operation. Telling InternalLockDisplay to wait for the user lock will
thus deadlock, so don't do that.

Signed-off-by: Keith Packard <keithp@keithp.com>
---

I don't know how this could ever have failed to deadlock --
sync_while_locked has called _XUserLockDisplay, and so locking_level
is non-zero. When _XInternalLockDisplay finds locking_level > 0, it
then calls _XDisplayLockWait, which is going to hang around for a
*very long time* as the lock is held by the current thread.

This patch fixes my application nicely, but I'd love to have someone
sanity check this...

 src/XlibInt.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/XlibInt.c b/src/XlibInt.c
index a8f5d08..12b816f 100644
--- a/src/XlibInt.c
+++ b/src/XlibInt.c
@@ -214,7 +214,7 @@  void sync_while_locked(Display *dpy)
 #endif
     UnlockDisplay(dpy);
     SyncHandle();
-    InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+    InternalLockDisplay(dpy, /* skip user locks */ 1);
 #ifdef XTHREADS
     if (dpy->lock)
         (*dpy->lock->user_unlock_display)(dpy);

Comments

<#part sign=pgpmime>
On Sat,  3 Mar 2012 02:08:03 -0800, Keith Packard <keithp@keithp.com> wrote:

> sync_while_locked grabs the user lock before performing the sync
> operation. Telling InternalLockDisplay to wait for the user lock will
> thus deadlock, so don't do that.

I've managed to create a short test case for this problem. It uses
two threads, one allocating IDs and the other calling XPending. Both
threads run as fast as possible, each checking to make sure the other
one is still running and aborting when one gets stuck. After a few
seconds of run time, the thread calling XPending gets stuck.

/*
 * Test Xlib sync_while_locked bug
 *
 *
 * Compile with:

 cc -o lockcheck -g lockcheck.c `pkg-config --cflags --libs x11` -lpthread

*/

#include <pthread.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

Display	*dpy;

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;

time_t	pending_time;
time_t	alloc_time;

void
check(void)
{
	time_t	now = time(NULL);
	pthread_mutex_lock(&fastmutex);
	if ((long) (now - pending_time) > 10) {
		printf ("pending thread stuck\n");
		abort();
	}
	if ((long) (now - alloc_time) > 10) {
		printf ("alloc thread stuck\n");
		abort();
	}
	pthread_mutex_unlock(&fastmutex);
}

static void *
run_pending (void *closure)
{
	int	i;
	for (;;) {
		pending_time = time(NULL);
		XPending(dpy);
		check();
	}
}

static void *
run_alloc (void *closure)
{
	for (;;) {
		alloc_time = time(NULL);
		XFreeGC(dpy, XCreateGC(dpy, RootWindow(dpy, 0), 0, NULL));
		check();
	}
}

main ()
{
	pthread_t	other_thread;

	XInitThreads();
	dpy = XOpenDisplay(NULL);
	pthread_create (&other_thread, 0, run_pending, 0);
	run_alloc(0);
}