[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