Test that doing wl_display.sync on a wrapped proxy with a special queue works as expected.
Test that creating a wrapper on a destroyed but not freed proxy fails. Signed-off-by: Jonas Ådahl <[email protected]> --- Changes since v1: - Adepted to the API changes - Added a test for ensuring that a wrapper for a destroyed proxy isn't created Jonas tests/queue-test.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/tests/queue-test.c b/tests/queue-test.c index 02865ae..917632c 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,184 @@ 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_display *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(display); + assert(display_wrapper); + wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); + callback = wl_display_sync(display_wrapper); + wl_proxy_wrapper_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 +client_test_queue_wrap_destroyed_proxy(void) +{ + struct wl_display *display; + struct wl_event_queue *queue; + struct wl_callback *callback; + struct wl_callback *callback_wrapper; + + display = wl_display_connect(NULL); + assert(display); + + queue = wl_display_create_queue(display); + assert(queue); + + callback = wl_display_sync(display); + assert(callback); + wl_proxy_set_queue((struct wl_proxy *) callback, queue); + + wl_display_roundtrip(display); + + /* The callback will now be queued in 'queue'. */ + wl_callback_destroy(callback); + + callback_wrapper = wl_proxy_create_wrapper(callback); + assert(!callback_wrapper); + + wl_event_queue_destroy(queue); + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -259,3 +441,27 @@ TEST(queue_roundtrip) display_destroy(d); } + +TEST(queue_set_queue_race) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_set_queue_race); + display_run(d); + + display_destroy(d); +} + +TEST(queue_wrap_destroyed_proxy) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_wrap_destroyed_proxy); + display_run(d); + + display_destroy(d); +} -- 2.5.5 _______________________________________________ wayland-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/wayland-devel
