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

Signed-off-by: Jonas Ådahl <jad...@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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to