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