Good morning everyone,

On 08.05.2013 23:30, Uli Schlachter wrote:
[...]
> Ah, after writing the rest of this mail, I just had this idea:
> 
> - X11 has taken the socket
> - Thread A has locked the display.
> - Thread B does xcb_no_operation() and thus ends up in libX11's 
> return_socket(),
> waiting for the display lock.
> - Thread A calls e.g. xcb_no_operation(), too, ends up in return_socket() and
> because socket_moving == 1, ends up waiting for thread B
> 
> => Deadlock
> 
> Is this the issue you are seeing and which should be described better in the
> commit message? What are the actual functions involved in this? How mad would
> you be if I blamed libX11 for this? ;-)

Attached is a small test program to test this theory and this does indeed cause
a deadlock. However, I still wouldn't call this situation "classic", because
this involves waiting on a condition variable.

Is this the problem you are trying to fix?

It would be nice if the commit somehow referenced this so that, if this patch
ever causes any problems, we can test new patches against it.

[...]
>> Signed-off-by: Christian König <christian.koe...@amd.com>
[...]

I noticed that the patch is from a different mail address than your mail. Is
this intentional? Why?

Cheers,
Uli
-- 
Bruce Schneier can read and understand Perl programs.
#define _GNU_SOURCE /* For PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>

static xcb_connection_t *connection;
static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static int owns_socket = 0;

static void lock(void)
{
	int res = pthread_mutex_lock(&mutex);
	if (res != 0)
		perror("mutex_lock");
}

static void unlock(void)
{
	int res = pthread_mutex_unlock(&mutex);
	if (res != 0)
		perror("mutex_lock");
}

static void wait_a_little(void)
{
	struct timespec tm;
	int i;

	/* 10 milliseconds */
	tm.tv_sec = 0;
	tm.tv_nsec = 1000000000 / 100;
	i = nanosleep(&tm, NULL);
	if (i != 0)
		perror("nanosleep");
}

static void put(char c)
{
	putchar(c);
	fflush(stdout);
}

static void return_socket(void *arg)
{
	(void) arg;
	lock();
	puts("Returning socket");
	if (!owns_socket)
		fprintf(stderr, "We aren't owning the socket?!\n");
	owns_socket = 0;
	unlock();
}

static void *thread_func(void *arg)
{
	uint64_t unused;
	(void) arg;
	while (1) {
		lock();
		if (!owns_socket) {
			xcb_take_socket(connection, return_socket, NULL, 0, &unused);
			put('t'); /* Took socket */
			owns_socket = 1;
		}
		wait_a_little();
		put('o'); /* nO operation */
		xcb_no_operation(connection);
		unlock();
	}

	return NULL;
}

int main(void)
{
	pthread_t thread;

	connection = xcb_connect(NULL, NULL);
	if (xcb_connection_has_error(connection)) {
		fprintf(stderr, "Failed to connect");
		return 1;
	}

	if (pthread_create(&thread, NULL, thread_func, NULL) != 0)
		perror("Failed to create thread");

	while (1) {
		put('n'); /* No operation */
		xcb_no_operation(connection);
	}

	pthread_join(thread, NULL);
	return 0;
}
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to