[RFC wayland 2/2] tests/queue-test: Add test for proxy wrappers

Jonas Ådahl jadahl at gmail.com
Mon Jun 29 04:30:36 PDT 2015


Test that doing wl_display.sync on a wrapped proxy with a special queue
works as expected.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
 tests/queue-test.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)

diff --git a/tests/queue-test.c b/tests/queue-test.c
index dc1a01d..fc384ed 100644
--- a/tests/queue-test.c
+++ b/tests/queue-test.c
@@ -23,6 +23,8 @@
  * SOFTWARE.
  */
 
+#define _GNU_SOURCE /* Needed for pthread_yield() */
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdbool.h>
@@ -30,6 +32,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <assert.h>
+#include <poll.h>
+#include <pthread.h>
 
 #include "wayland-client.h"
 #include "wayland-server.h"
@@ -204,6 +208,154 @@ client_test_queue_roundtrip(void)
 	wl_display_disconnect(display);
 }
 
+struct thread_info {
+	struct wl_display *display;
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	bool run;
+	bool dispatch_roundtrip_done;
+};
+
+static void *
+dispatcher_thread_run(void *arg)
+{
+	struct thread_info *info = arg;
+	struct pollfd pfd;
+	struct wl_callback *callback;
+	int ret;
+
+	pfd.fd = wl_display_get_fd(info->display);
+	pfd.events = POLLIN;
+
+	/* Simple command "queue" that does a round trip every time its woken
+	 * up until its terminated (by setting info->run to false).
+	 */
+	pthread_mutex_lock(&info->mutex);
+	do {
+		pthread_cond_wait(&info->cond, &info->mutex);
+		if (!info->run)
+			break;
+
+		assert(!info->dispatch_roundtrip_done);
+		callback = wl_display_sync(info->display);
+		wl_callback_add_listener(callback,
+					 &sync_listener_roundtrip,
+					 &info->dispatch_roundtrip_done);
+		wl_display_flush(info->display);
+		while (true) {
+			while (true) {
+				ret = wl_display_dispatch_pending(info->display);
+				assert(ret >= 0);
+				if (ret == 0)
+					break;
+			}
+
+			if (info->dispatch_roundtrip_done)
+				break;
+
+			assert(wl_display_prepare_read(info->display) == 0);
+			assert(poll(&pfd, 1, -1) == 1);
+			assert(wl_display_read_events(info->display) == 0);
+		}
+		wl_callback_destroy(callback);
+	} while (true);
+	pthread_mutex_unlock(&info->mutex);
+
+	return NULL;
+}
+
+static void
+wait_for_dispatch_thread_roundtrip(struct thread_info *info)
+{
+	pthread_mutex_lock(&info->mutex);
+	info->dispatch_roundtrip_done = false;
+	pthread_cond_signal(&info->cond);
+	pthread_mutex_unlock(&info->mutex);
+	pthread_yield();
+
+	while (true) {
+		pthread_mutex_lock(&info->mutex);
+		if (info->dispatch_roundtrip_done) {
+			pthread_mutex_unlock(&info->mutex);
+			break;
+		}
+		pthread_cond_signal(&info->cond);
+		pthread_mutex_unlock(&info->mutex);
+	}
+}
+
+static void
+client_test_queue_set_queue_race(void)
+{
+	DISABLE_LEAK_CHECKS;
+
+	struct wl_event_queue *queue;
+	struct wl_display *display;
+	struct wl_proxy *display_wrapper;
+	struct thread_info info;
+	pthread_t dispatcher_thread;
+	struct wl_callback *callback;
+	bool done = false;
+	struct pollfd pfd;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	info = (struct thread_info) {
+		.display = display,
+		.run = true,
+		.mutex = PTHREAD_MUTEX_INITIALIZER,
+		.cond = PTHREAD_COND_INITIALIZER,
+	};
+	assert(pthread_create(&dispatcher_thread,
+			      NULL,
+			      dispatcher_thread_run,
+			      &info) == 0);
+
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	display_wrapper = wl_proxy_create_wrapper((struct wl_proxy *) display);
+	assert(display_wrapper);
+	wl_proxy_set_queue(display_wrapper, queue);
+	callback = wl_display_sync((struct wl_display *)display_wrapper);
+	wl_proxy_destroy(display_wrapper);
+	assert(callback != NULL);
+
+	/* Check that the dispatcher thread didn't dispatch the event. */
+	wait_for_dispatch_thread_roundtrip(&info);
+
+	wl_callback_add_listener(callback, &sync_listener_roundtrip, &done);
+	wl_display_flush(display);
+
+	assert(!done);
+
+	pfd.fd = wl_display_get_fd(info.display);
+	pfd.events = POLLIN;
+
+	while (true) {
+		while (wl_display_prepare_read_queue(display, queue) != 0)
+			wl_display_dispatch_queue_pending(display, queue);
+
+		if (done)
+			break;
+
+		assert(poll(&pfd, 1, -1) == 1);
+		assert(wl_display_read_events(display) == 0);
+	}
+
+	wl_callback_destroy(callback);
+	wl_event_queue_destroy(queue);
+
+	info.run = false;
+	pthread_mutex_lock(&info.mutex);
+	pthread_cond_signal(&info.cond);
+	pthread_mutex_unlock(&info.mutex);
+	pthread_join(dispatcher_thread, NULL);
+
+	wl_display_disconnect(display);
+}
+
 static void
 dummy_bind(struct wl_client *client,
 	   void *data, uint32_t version, uint32_t id)
@@ -259,3 +411,15 @@ TEST(queue_roundtrip)
 
 	display_destroy(d);
 }
+
+TEST(queue_set_queue_race)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create(d, client_test_queue_set_queue_race);
+	display_run(d);
+
+	display_destroy(d);
+}
-- 
2.1.4



More information about the wayland-devel mailing list