xref: /aosp_15_r20/external/wayland/tests/queue-test.c (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
1*84e872a0SLloyd Pique /*
2*84e872a0SLloyd Pique  * Copyright © 2012 Jonas Ådahl
3*84e872a0SLloyd Pique  *
4*84e872a0SLloyd Pique  * Permission is hereby granted, free of charge, to any person obtaining
5*84e872a0SLloyd Pique  * a copy of this software and associated documentation files (the
6*84e872a0SLloyd Pique  * "Software"), to deal in the Software without restriction, including
7*84e872a0SLloyd Pique  * without limitation the rights to use, copy, modify, merge, publish,
8*84e872a0SLloyd Pique  * distribute, sublicense, and/or sell copies of the Software, and to
9*84e872a0SLloyd Pique  * permit persons to whom the Software is furnished to do so, subject to
10*84e872a0SLloyd Pique  * the following conditions:
11*84e872a0SLloyd Pique  *
12*84e872a0SLloyd Pique  * The above copyright notice and this permission notice (including the
13*84e872a0SLloyd Pique  * next paragraph) shall be included in all copies or substantial
14*84e872a0SLloyd Pique  * portions of the Software.
15*84e872a0SLloyd Pique  *
16*84e872a0SLloyd Pique  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*84e872a0SLloyd Pique  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*84e872a0SLloyd Pique  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*84e872a0SLloyd Pique  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20*84e872a0SLloyd Pique  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21*84e872a0SLloyd Pique  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22*84e872a0SLloyd Pique  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*84e872a0SLloyd Pique  * SOFTWARE.
24*84e872a0SLloyd Pique  */
25*84e872a0SLloyd Pique 
26*84e872a0SLloyd Pique #define _GNU_SOURCE /* For memrchr */
27*84e872a0SLloyd Pique #include <stdlib.h>
28*84e872a0SLloyd Pique #include <stdint.h>
29*84e872a0SLloyd Pique #include <stdio.h>
30*84e872a0SLloyd Pique #include <stdbool.h>
31*84e872a0SLloyd Pique #include <string.h>
32*84e872a0SLloyd Pique #include <unistd.h>
33*84e872a0SLloyd Pique #include <sys/mman.h>
34*84e872a0SLloyd Pique #include <sys/types.h>
35*84e872a0SLloyd Pique #include <sys/wait.h>
36*84e872a0SLloyd Pique #include <assert.h>
37*84e872a0SLloyd Pique #include <signal.h>
38*84e872a0SLloyd Pique 
39*84e872a0SLloyd Pique #include "wayland-client.h"
40*84e872a0SLloyd Pique #include "wayland-server.h"
41*84e872a0SLloyd Pique #include "test-runner.h"
42*84e872a0SLloyd Pique #include "test-compositor.h"
43*84e872a0SLloyd Pique 
44*84e872a0SLloyd Pique #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
45*84e872a0SLloyd Pique 
46*84e872a0SLloyd Pique static void
registry_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)47*84e872a0SLloyd Pique registry_handle_global(void *data, struct wl_registry *registry,
48*84e872a0SLloyd Pique 		       uint32_t id, const char *interface, uint32_t version)
49*84e872a0SLloyd Pique {
50*84e872a0SLloyd Pique 	int *pcounter = data;
51*84e872a0SLloyd Pique 	(*pcounter)++;
52*84e872a0SLloyd Pique 	assert(*pcounter == 1);
53*84e872a0SLloyd Pique 	wl_registry_destroy(registry);
54*84e872a0SLloyd Pique }
55*84e872a0SLloyd Pique 
56*84e872a0SLloyd Pique static const struct wl_registry_listener registry_listener = {
57*84e872a0SLloyd Pique 	registry_handle_global,
58*84e872a0SLloyd Pique 	NULL
59*84e872a0SLloyd Pique };
60*84e872a0SLloyd Pique 
61*84e872a0SLloyd Pique /* Test that destroying a proxy object doesn't result in any more
62*84e872a0SLloyd Pique  * callback being invoked, even though were many queued. */
63*84e872a0SLloyd Pique static void
client_test_proxy_destroy(void)64*84e872a0SLloyd Pique client_test_proxy_destroy(void)
65*84e872a0SLloyd Pique {
66*84e872a0SLloyd Pique 	struct wl_display *display;
67*84e872a0SLloyd Pique 	struct wl_registry *registry;
68*84e872a0SLloyd Pique 	int counter = 0;
69*84e872a0SLloyd Pique 
70*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
71*84e872a0SLloyd Pique 	assert(display);
72*84e872a0SLloyd Pique 
73*84e872a0SLloyd Pique 	registry = wl_display_get_registry(display);
74*84e872a0SLloyd Pique 	assert(registry != NULL);
75*84e872a0SLloyd Pique 	wl_registry_add_listener(registry, &registry_listener,
76*84e872a0SLloyd Pique 				 &counter);
77*84e872a0SLloyd Pique 	assert(wl_display_roundtrip(display) != -1);
78*84e872a0SLloyd Pique 
79*84e872a0SLloyd Pique 	assert(counter == 1);
80*84e872a0SLloyd Pique 
81*84e872a0SLloyd Pique 	/* don't destroy the registry, we have already destroyed them
82*84e872a0SLloyd Pique 	 * in the global handler */
83*84e872a0SLloyd Pique 	wl_display_disconnect(display);
84*84e872a0SLloyd Pique }
85*84e872a0SLloyd Pique 
86*84e872a0SLloyd Pique struct multiple_queues_state {
87*84e872a0SLloyd Pique 	struct wl_display *display;
88*84e872a0SLloyd Pique 	struct wl_callback* callback2;
89*84e872a0SLloyd Pique 	bool done;
90*84e872a0SLloyd Pique };
91*84e872a0SLloyd Pique 
92*84e872a0SLloyd Pique static void
sync_callback(void * data,struct wl_callback * callback,uint32_t serial)93*84e872a0SLloyd Pique sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
94*84e872a0SLloyd Pique {
95*84e872a0SLloyd Pique 	struct multiple_queues_state *state = data;
96*84e872a0SLloyd Pique 
97*84e872a0SLloyd Pique 	state->done = true;
98*84e872a0SLloyd Pique 	wl_callback_destroy(callback);
99*84e872a0SLloyd Pique 
100*84e872a0SLloyd Pique 	wl_display_dispatch_pending(state->display);
101*84e872a0SLloyd Pique 
102*84e872a0SLloyd Pique 	wl_callback_destroy(state->callback2);
103*84e872a0SLloyd Pique }
104*84e872a0SLloyd Pique 
105*84e872a0SLloyd Pique static const struct wl_callback_listener sync_listener = {
106*84e872a0SLloyd Pique 	sync_callback
107*84e872a0SLloyd Pique };
108*84e872a0SLloyd Pique 
109*84e872a0SLloyd Pique /* Test that when receiving the first of two synchronization
110*84e872a0SLloyd Pique  * callback events, destroying the second one doesn't cause any
111*84e872a0SLloyd Pique  * errors even if the delete_id event is handled out of order. */
112*84e872a0SLloyd Pique static void
client_test_multiple_queues(void)113*84e872a0SLloyd Pique client_test_multiple_queues(void)
114*84e872a0SLloyd Pique {
115*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
116*84e872a0SLloyd Pique 	struct wl_callback *callback1;
117*84e872a0SLloyd Pique 	struct multiple_queues_state state;
118*84e872a0SLloyd Pique 	int ret = 0;
119*84e872a0SLloyd Pique 
120*84e872a0SLloyd Pique 	state.display = wl_display_connect(NULL);
121*84e872a0SLloyd Pique 	assert(state.display);
122*84e872a0SLloyd Pique 
123*84e872a0SLloyd Pique 	queue = wl_display_create_queue(state.display);
124*84e872a0SLloyd Pique 	assert(queue);
125*84e872a0SLloyd Pique 
126*84e872a0SLloyd Pique 	state.done = false;
127*84e872a0SLloyd Pique 	callback1 = wl_display_sync(state.display);
128*84e872a0SLloyd Pique 	assert(callback1 != NULL);
129*84e872a0SLloyd Pique 	wl_callback_add_listener(callback1, &sync_listener, &state);
130*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) callback1, queue);
131*84e872a0SLloyd Pique 
132*84e872a0SLloyd Pique 	state.callback2 = wl_display_sync(state.display);
133*84e872a0SLloyd Pique 	assert(state.callback2 != NULL);
134*84e872a0SLloyd Pique 	wl_callback_add_listener(state.callback2, &sync_listener, NULL);
135*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) state.callback2, queue);
136*84e872a0SLloyd Pique 
137*84e872a0SLloyd Pique 	wl_display_flush(state.display);
138*84e872a0SLloyd Pique 
139*84e872a0SLloyd Pique 	while (!state.done && !ret)
140*84e872a0SLloyd Pique 		ret = wl_display_dispatch_queue(state.display, queue);
141*84e872a0SLloyd Pique 
142*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
143*84e872a0SLloyd Pique 	wl_display_disconnect(state.display);
144*84e872a0SLloyd Pique 
145*84e872a0SLloyd Pique 	exit(ret == -1 ? -1 : 0);
146*84e872a0SLloyd Pique }
147*84e872a0SLloyd Pique 
148*84e872a0SLloyd Pique static void
sync_callback_roundtrip(void * data,struct wl_callback * callback,uint32_t serial)149*84e872a0SLloyd Pique sync_callback_roundtrip(void *data, struct wl_callback *callback, uint32_t serial)
150*84e872a0SLloyd Pique {
151*84e872a0SLloyd Pique 	bool *done = data;
152*84e872a0SLloyd Pique 	*done = true;
153*84e872a0SLloyd Pique }
154*84e872a0SLloyd Pique 
155*84e872a0SLloyd Pique static const struct wl_callback_listener sync_listener_roundtrip = {
156*84e872a0SLloyd Pique 	sync_callback_roundtrip
157*84e872a0SLloyd Pique };
158*84e872a0SLloyd Pique 
159*84e872a0SLloyd Pique /* Test that doing a roundtrip on a queue only the events on that
160*84e872a0SLloyd Pique  * queue get dispatched. */
161*84e872a0SLloyd Pique static void
client_test_queue_roundtrip(void)162*84e872a0SLloyd Pique client_test_queue_roundtrip(void)
163*84e872a0SLloyd Pique {
164*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
165*84e872a0SLloyd Pique 	struct wl_callback *callback1;
166*84e872a0SLloyd Pique 	struct wl_callback *callback2;
167*84e872a0SLloyd Pique 	struct wl_display *display;
168*84e872a0SLloyd Pique 	bool done1 = false;
169*84e872a0SLloyd Pique 	bool done2 = false;
170*84e872a0SLloyd Pique 
171*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
172*84e872a0SLloyd Pique 	assert(display);
173*84e872a0SLloyd Pique 
174*84e872a0SLloyd Pique 	queue = wl_display_create_queue(display);
175*84e872a0SLloyd Pique 	assert(queue);
176*84e872a0SLloyd Pique 
177*84e872a0SLloyd Pique 	/* arm a callback on the default queue */
178*84e872a0SLloyd Pique 	callback1 = wl_display_sync(display);
179*84e872a0SLloyd Pique 	assert(callback1 != NULL);
180*84e872a0SLloyd Pique 	wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
181*84e872a0SLloyd Pique 
182*84e872a0SLloyd Pique 	/* arm a callback on the other queue */
183*84e872a0SLloyd Pique 	callback2 = wl_display_sync(display);
184*84e872a0SLloyd Pique 	assert(callback2 != NULL);
185*84e872a0SLloyd Pique 	wl_callback_add_listener(callback2, &sync_listener_roundtrip, &done2);
186*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) callback2, queue);
187*84e872a0SLloyd Pique 
188*84e872a0SLloyd Pique 	/* roundtrip on default queue must not dispatch the other queue. */
189*84e872a0SLloyd Pique 	wl_display_roundtrip(display);
190*84e872a0SLloyd Pique 	assert(done1 == true);
191*84e872a0SLloyd Pique 	assert(done2 == false);
192*84e872a0SLloyd Pique 
193*84e872a0SLloyd Pique 	/* re-arm the sync callback on the default queue, so we see that
194*84e872a0SLloyd Pique 	 * wl_display_roundtrip_queue() does not dispatch the default queue. */
195*84e872a0SLloyd Pique 	wl_callback_destroy(callback1);
196*84e872a0SLloyd Pique 	done1 = false;
197*84e872a0SLloyd Pique 	callback1 = wl_display_sync(display);
198*84e872a0SLloyd Pique 	assert(callback1 != NULL);
199*84e872a0SLloyd Pique 	wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
200*84e872a0SLloyd Pique 
201*84e872a0SLloyd Pique 	wl_display_roundtrip_queue(display, queue);
202*84e872a0SLloyd Pique 	assert(done1 == false);
203*84e872a0SLloyd Pique 	assert(done2 == true);
204*84e872a0SLloyd Pique 
205*84e872a0SLloyd Pique 	wl_callback_destroy(callback1);
206*84e872a0SLloyd Pique 	wl_callback_destroy(callback2);
207*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
208*84e872a0SLloyd Pique 
209*84e872a0SLloyd Pique 	wl_display_disconnect(display);
210*84e872a0SLloyd Pique }
211*84e872a0SLloyd Pique 
212*84e872a0SLloyd Pique static void
client_test_queue_proxy_wrapper(void)213*84e872a0SLloyd Pique client_test_queue_proxy_wrapper(void)
214*84e872a0SLloyd Pique {
215*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
216*84e872a0SLloyd Pique 	struct wl_display *display;
217*84e872a0SLloyd Pique 	struct wl_display *display_wrapper;
218*84e872a0SLloyd Pique 	struct wl_callback *callback;
219*84e872a0SLloyd Pique 	bool done = false;
220*84e872a0SLloyd Pique 
221*84e872a0SLloyd Pique 	/*
222*84e872a0SLloyd Pique 	 * For an illustration of what usage would normally fail without using
223*84e872a0SLloyd Pique 	 * proxy wrappers, see the `client_test_queue_set_queue_race' test case.
224*84e872a0SLloyd Pique 	 */
225*84e872a0SLloyd Pique 
226*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
227*84e872a0SLloyd Pique 	assert(display);
228*84e872a0SLloyd Pique 
229*84e872a0SLloyd Pique 	/* Pretend we are in a separate thread where a thread-local queue is
230*84e872a0SLloyd Pique 	 * used. */
231*84e872a0SLloyd Pique 	queue = wl_display_create_queue(display);
232*84e872a0SLloyd Pique 	assert(queue);
233*84e872a0SLloyd Pique 
234*84e872a0SLloyd Pique 	display_wrapper = wl_proxy_create_wrapper(display);
235*84e872a0SLloyd Pique 	assert(display_wrapper);
236*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
237*84e872a0SLloyd Pique 	callback = wl_display_sync(display_wrapper);
238*84e872a0SLloyd Pique 	wl_proxy_wrapper_destroy(display_wrapper);
239*84e872a0SLloyd Pique 	assert(callback != NULL);
240*84e872a0SLloyd Pique 
241*84e872a0SLloyd Pique 	/* Pretend we are now another thread and dispatch the dispatch the main
242*84e872a0SLloyd Pique 	 * queue while also knowing our callback is read and queued. */
243*84e872a0SLloyd Pique 	wl_display_roundtrip(display);
244*84e872a0SLloyd Pique 
245*84e872a0SLloyd Pique 	/* Make sure that the pretend-to-be main thread didn't dispatch our
246*84e872a0SLloyd Pique 	 * callback, behind our back. */
247*84e872a0SLloyd Pique 	wl_callback_add_listener(callback, &sync_listener_roundtrip, &done);
248*84e872a0SLloyd Pique 	wl_display_flush(display);
249*84e872a0SLloyd Pique 
250*84e872a0SLloyd Pique 	assert(!done);
251*84e872a0SLloyd Pique 
252*84e872a0SLloyd Pique 	/* Make sure that we eventually end up dispatching our callback. */
253*84e872a0SLloyd Pique 	while (!done)
254*84e872a0SLloyd Pique 		assert(wl_display_dispatch_queue(display, queue) != -1);
255*84e872a0SLloyd Pique 
256*84e872a0SLloyd Pique 	wl_callback_destroy(callback);
257*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
258*84e872a0SLloyd Pique 
259*84e872a0SLloyd Pique 	wl_display_disconnect(display);
260*84e872a0SLloyd Pique }
261*84e872a0SLloyd Pique 
262*84e872a0SLloyd Pique static void
client_test_queue_set_queue_race(void)263*84e872a0SLloyd Pique client_test_queue_set_queue_race(void)
264*84e872a0SLloyd Pique {
265*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
266*84e872a0SLloyd Pique 	struct wl_display *display;
267*84e872a0SLloyd Pique 	struct wl_callback *callback;
268*84e872a0SLloyd Pique 	bool done = false;
269*84e872a0SLloyd Pique 
270*84e872a0SLloyd Pique 	/*
271*84e872a0SLloyd Pique 	 * This test illustrates the multi threading scenario which would fail
272*84e872a0SLloyd Pique 	 * without doing what is done in the `client_test_queue_proxy_wrapper'
273*84e872a0SLloyd Pique 	 * test.
274*84e872a0SLloyd Pique 	 */
275*84e872a0SLloyd Pique 
276*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
277*84e872a0SLloyd Pique 	assert(display);
278*84e872a0SLloyd Pique 
279*84e872a0SLloyd Pique 	/* Pretend we are in a separate thread where a thread-local queue is
280*84e872a0SLloyd Pique 	 * used. */
281*84e872a0SLloyd Pique 	queue = wl_display_create_queue(display);
282*84e872a0SLloyd Pique 	assert(queue);
283*84e872a0SLloyd Pique 
284*84e872a0SLloyd Pique 	callback = wl_display_sync(display);
285*84e872a0SLloyd Pique 	assert(callback != NULL);
286*84e872a0SLloyd Pique 
287*84e872a0SLloyd Pique 	/* Pretend we are now another thread and dispatch the dispatch the main
288*84e872a0SLloyd Pique 	 * queue while also knowing our callback is read, queued on the wrong
289*84e872a0SLloyd Pique 	 * queue, and dispatched. */
290*84e872a0SLloyd Pique 	wl_display_roundtrip(display);
291*84e872a0SLloyd Pique 
292*84e872a0SLloyd Pique 	/* Pretend we are back in the separate thread, and continue with setting
293*84e872a0SLloyd Pique 	 * up our callback. */
294*84e872a0SLloyd Pique 	wl_callback_add_listener(callback, &sync_listener_roundtrip, &done);
295*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) callback, queue);
296*84e872a0SLloyd Pique 
297*84e872a0SLloyd Pique 	/* Roundtrip our separate thread queue to make sure any events are
298*84e872a0SLloyd Pique 	 * dispatched. */
299*84e872a0SLloyd Pique 	wl_display_roundtrip_queue(display, queue);
300*84e872a0SLloyd Pique 
301*84e872a0SLloyd Pique 	/* Verify that the callback has indeed been dropped. */
302*84e872a0SLloyd Pique 	assert(!done);
303*84e872a0SLloyd Pique 
304*84e872a0SLloyd Pique 	wl_callback_destroy(callback);
305*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
306*84e872a0SLloyd Pique 
307*84e872a0SLloyd Pique 	wl_display_disconnect(display);
308*84e872a0SLloyd Pique }
309*84e872a0SLloyd Pique 
310*84e872a0SLloyd Pique static char *
maybe_map_file(int fd,size_t * len)311*84e872a0SLloyd Pique maybe_map_file(int fd, size_t *len)
312*84e872a0SLloyd Pique {
313*84e872a0SLloyd Pique 	char *data;
314*84e872a0SLloyd Pique 
315*84e872a0SLloyd Pique 	*len = lseek(fd, 0, SEEK_END);
316*84e872a0SLloyd Pique 	data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
317*84e872a0SLloyd Pique 
318*84e872a0SLloyd Pique 	return data;
319*84e872a0SLloyd Pique }
320*84e872a0SLloyd Pique 
321*84e872a0SLloyd Pique static char *
map_file(int fd,size_t * len)322*84e872a0SLloyd Pique map_file(int fd, size_t *len)
323*84e872a0SLloyd Pique {
324*84e872a0SLloyd Pique 	char *data;
325*84e872a0SLloyd Pique 
326*84e872a0SLloyd Pique 	data = maybe_map_file(fd, len);
327*84e872a0SLloyd Pique 	assert(data != MAP_FAILED && "Failed to mmap file");
328*84e872a0SLloyd Pique 
329*84e872a0SLloyd Pique 	return data;
330*84e872a0SLloyd Pique }
331*84e872a0SLloyd Pique 
332*84e872a0SLloyd Pique static char *
last_line_of(char * s)333*84e872a0SLloyd Pique last_line_of(char *s)
334*84e872a0SLloyd Pique {
335*84e872a0SLloyd Pique 	size_t len = strlen(s);
336*84e872a0SLloyd Pique 	char *last;
337*84e872a0SLloyd Pique 
338*84e872a0SLloyd Pique 	last = memrchr(s, '\n', len);
339*84e872a0SLloyd Pique 	/* If we found a newline at end of string, find the previous one. */
340*84e872a0SLloyd Pique 	if (last && last[1] == 0)
341*84e872a0SLloyd Pique 		last = memrchr(s, '\n', len - 1);
342*84e872a0SLloyd Pique 	/* If we have a newline, the last line starts after the newline.
343*84e872a0SLloyd Pique 	 * Otherwise, the whole string is the last line. */
344*84e872a0SLloyd Pique 	if (last)
345*84e872a0SLloyd Pique 		last += 1;
346*84e872a0SLloyd Pique 	else
347*84e872a0SLloyd Pique 		last = s;
348*84e872a0SLloyd Pique 
349*84e872a0SLloyd Pique 	return last;
350*84e872a0SLloyd Pique }
351*84e872a0SLloyd Pique 
352*84e872a0SLloyd Pique static void
client_test_queue_destroy_with_attached_proxies(void)353*84e872a0SLloyd Pique client_test_queue_destroy_with_attached_proxies(void)
354*84e872a0SLloyd Pique {
355*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
356*84e872a0SLloyd Pique 	struct wl_display *display;
357*84e872a0SLloyd Pique 	struct wl_display *display_wrapper;
358*84e872a0SLloyd Pique 	struct wl_callback *callback;
359*84e872a0SLloyd Pique 	char *log;
360*84e872a0SLloyd Pique 	size_t log_len;
361*84e872a0SLloyd Pique 	char callback_name[24];
362*84e872a0SLloyd Pique 	int ret;
363*84e872a0SLloyd Pique 
364*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
365*84e872a0SLloyd Pique 	assert(display);
366*84e872a0SLloyd Pique 
367*84e872a0SLloyd Pique 	/* Pretend we are in a separate thread where a thread-local queue is
368*84e872a0SLloyd Pique 	 * used. */
369*84e872a0SLloyd Pique 	queue = wl_display_create_queue(display);
370*84e872a0SLloyd Pique 	assert(queue);
371*84e872a0SLloyd Pique 
372*84e872a0SLloyd Pique 	/* Create a sync dispatching events on the thread-local queue. */
373*84e872a0SLloyd Pique 	display_wrapper = wl_proxy_create_wrapper(display);
374*84e872a0SLloyd Pique 	assert(display_wrapper);
375*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
376*84e872a0SLloyd Pique 	callback = wl_display_sync(display_wrapper);
377*84e872a0SLloyd Pique 	wl_proxy_wrapper_destroy(display_wrapper);
378*84e872a0SLloyd Pique 	assert(callback != NULL);
379*84e872a0SLloyd Pique 
380*84e872a0SLloyd Pique 	/* Destroy the queue before the attached object. */
381*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
382*84e872a0SLloyd Pique 
383*84e872a0SLloyd Pique 	/* Check that the log contains some information about the attached
384*84e872a0SLloyd Pique 	 * wl_callback proxy. */
385*84e872a0SLloyd Pique 	log = map_file(client_log_fd, &log_len);
386*84e872a0SLloyd Pique 	ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
387*84e872a0SLloyd Pique 		       wl_proxy_get_id((struct wl_proxy *) callback));
388*84e872a0SLloyd Pique 	assert(ret > 0 && ret < (int)sizeof(callback_name) &&
389*84e872a0SLloyd Pique 	       "callback name creation failed (possibly truncated)");
390*84e872a0SLloyd Pique 	assert(strstr(last_line_of(log), callback_name));
391*84e872a0SLloyd Pique 	munmap(log, log_len);
392*84e872a0SLloyd Pique 
393*84e872a0SLloyd Pique 	wl_callback_destroy(callback);
394*84e872a0SLloyd Pique 
395*84e872a0SLloyd Pique 	wl_display_disconnect(display);
396*84e872a0SLloyd Pique }
397*84e872a0SLloyd Pique 
398*84e872a0SLloyd Pique static void
client_test_queue_proxy_event_to_destroyed_queue(void)399*84e872a0SLloyd Pique client_test_queue_proxy_event_to_destroyed_queue(void)
400*84e872a0SLloyd Pique {
401*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
402*84e872a0SLloyd Pique 	struct wl_display *display;
403*84e872a0SLloyd Pique 	struct wl_display *display_wrapper;
404*84e872a0SLloyd Pique 	struct wl_callback *callback;
405*84e872a0SLloyd Pique 
406*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
407*84e872a0SLloyd Pique 	assert(display);
408*84e872a0SLloyd Pique 
409*84e872a0SLloyd Pique 	/* Pretend we are in a separate thread where a thread-local queue is
410*84e872a0SLloyd Pique 	 * used. */
411*84e872a0SLloyd Pique 	queue = wl_display_create_queue(display);
412*84e872a0SLloyd Pique 	assert(queue);
413*84e872a0SLloyd Pique 
414*84e872a0SLloyd Pique 	/* Create a sync dispatching events on the thread-local queue. */
415*84e872a0SLloyd Pique 	display_wrapper = wl_proxy_create_wrapper(display);
416*84e872a0SLloyd Pique 	assert(display_wrapper);
417*84e872a0SLloyd Pique 	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
418*84e872a0SLloyd Pique 	callback = wl_display_sync(display_wrapper);
419*84e872a0SLloyd Pique 	wl_proxy_wrapper_destroy(display_wrapper);
420*84e872a0SLloyd Pique 	assert(callback != NULL);
421*84e872a0SLloyd Pique 	wl_display_flush(display);
422*84e872a0SLloyd Pique 
423*84e872a0SLloyd Pique 	/* Destroy the queue before the attached object. */
424*84e872a0SLloyd Pique 	wl_event_queue_destroy(queue);
425*84e872a0SLloyd Pique 
426*84e872a0SLloyd Pique 	/* During this roundtrip we should receive the done event on 'callback',
427*84e872a0SLloyd Pique 	 * try to queue it to the destroyed queue, and abort. */
428*84e872a0SLloyd Pique 	wl_display_roundtrip(display);
429*84e872a0SLloyd Pique 
430*84e872a0SLloyd Pique 	wl_callback_destroy(callback);
431*84e872a0SLloyd Pique 
432*84e872a0SLloyd Pique 	wl_display_disconnect(display);
433*84e872a0SLloyd Pique }
434*84e872a0SLloyd Pique 
435*84e872a0SLloyd Pique static void
client_test_queue_destroy_default_with_attached_proxies(void)436*84e872a0SLloyd Pique client_test_queue_destroy_default_with_attached_proxies(void)
437*84e872a0SLloyd Pique {
438*84e872a0SLloyd Pique 	struct wl_display *display;
439*84e872a0SLloyd Pique 	struct wl_callback *callback;
440*84e872a0SLloyd Pique 	char *log;
441*84e872a0SLloyd Pique 	size_t log_len;
442*84e872a0SLloyd Pique 	char callback_name[24];
443*84e872a0SLloyd Pique 	int ret;
444*84e872a0SLloyd Pique 
445*84e872a0SLloyd Pique 	display = wl_display_connect(NULL);
446*84e872a0SLloyd Pique 	assert(display);
447*84e872a0SLloyd Pique 
448*84e872a0SLloyd Pique 	/* Create a sync dispatching events on the default queue. */
449*84e872a0SLloyd Pique 	callback = wl_display_sync(display);
450*84e872a0SLloyd Pique 	assert(callback != NULL);
451*84e872a0SLloyd Pique 
452*84e872a0SLloyd Pique 	/* Destroy the default queue (by disconnecting) before the attached
453*84e872a0SLloyd Pique 	 * object. */
454*84e872a0SLloyd Pique 	wl_display_disconnect(display);
455*84e872a0SLloyd Pique 
456*84e872a0SLloyd Pique 	/* Check that the log does not contain any warning about the attached
457*84e872a0SLloyd Pique 	 * wl_callback proxy. */
458*84e872a0SLloyd Pique 	log = maybe_map_file(client_log_fd, &log_len);
459*84e872a0SLloyd Pique 	ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
460*84e872a0SLloyd Pique 		       wl_proxy_get_id((struct wl_proxy *) callback));
461*84e872a0SLloyd Pique 	assert(ret > 0 && ret < (int)sizeof(callback_name) &&
462*84e872a0SLloyd Pique 	       "callback name creation failed (possibly truncated)");
463*84e872a0SLloyd Pique 	assert(log == MAP_FAILED || strstr(log, callback_name) == NULL);
464*84e872a0SLloyd Pique 	if (log != MAP_FAILED)
465*84e872a0SLloyd Pique 		munmap(log, log_len);
466*84e872a0SLloyd Pique 
467*84e872a0SLloyd Pique 	/* HACK: Directly free the memory of the wl_callback proxy to appease
468*84e872a0SLloyd Pique 	 * ASan. We would normally use wl_callback_destroy(), but since we have
469*84e872a0SLloyd Pique 	 * destroyed the associated wl_display, using this function would lead
470*84e872a0SLloyd Pique 	 * to memory errors. */
471*84e872a0SLloyd Pique 	free(callback);
472*84e872a0SLloyd Pique }
473*84e872a0SLloyd Pique 
474*84e872a0SLloyd Pique static void
dummy_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)475*84e872a0SLloyd Pique dummy_bind(struct wl_client *client,
476*84e872a0SLloyd Pique 	   void *data, uint32_t version, uint32_t id)
477*84e872a0SLloyd Pique {
478*84e872a0SLloyd Pique }
479*84e872a0SLloyd Pique 
TEST(queue_proxy_destroy)480*84e872a0SLloyd Pique TEST(queue_proxy_destroy)
481*84e872a0SLloyd Pique {
482*84e872a0SLloyd Pique 	struct display *d;
483*84e872a0SLloyd Pique 	const struct wl_interface *dummy_interfaces[] = {
484*84e872a0SLloyd Pique 		&wl_seat_interface,
485*84e872a0SLloyd Pique 		&wl_pointer_interface,
486*84e872a0SLloyd Pique 		&wl_keyboard_interface,
487*84e872a0SLloyd Pique 		&wl_surface_interface
488*84e872a0SLloyd Pique 	};
489*84e872a0SLloyd Pique 	unsigned int i;
490*84e872a0SLloyd Pique 
491*84e872a0SLloyd Pique 	d = display_create();
492*84e872a0SLloyd Pique 
493*84e872a0SLloyd Pique 	for (i = 0; i < ARRAY_LENGTH(dummy_interfaces); i++)
494*84e872a0SLloyd Pique 		wl_global_create(d->wl_display, dummy_interfaces[i],
495*84e872a0SLloyd Pique 				 dummy_interfaces[i]->version,
496*84e872a0SLloyd Pique 				 NULL, dummy_bind);
497*84e872a0SLloyd Pique 
498*84e872a0SLloyd Pique 	test_set_timeout(2);
499*84e872a0SLloyd Pique 
500*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_proxy_destroy);
501*84e872a0SLloyd Pique 	display_run(d);
502*84e872a0SLloyd Pique 
503*84e872a0SLloyd Pique 	display_destroy(d);
504*84e872a0SLloyd Pique }
505*84e872a0SLloyd Pique 
TEST(queue_multiple_queues)506*84e872a0SLloyd Pique TEST(queue_multiple_queues)
507*84e872a0SLloyd Pique {
508*84e872a0SLloyd Pique 	struct display *d = display_create();
509*84e872a0SLloyd Pique 
510*84e872a0SLloyd Pique 	test_set_timeout(2);
511*84e872a0SLloyd Pique 
512*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_multiple_queues);
513*84e872a0SLloyd Pique 	display_run(d);
514*84e872a0SLloyd Pique 
515*84e872a0SLloyd Pique 	display_destroy(d);
516*84e872a0SLloyd Pique }
517*84e872a0SLloyd Pique 
TEST(queue_roundtrip)518*84e872a0SLloyd Pique TEST(queue_roundtrip)
519*84e872a0SLloyd Pique {
520*84e872a0SLloyd Pique 	struct display *d = display_create();
521*84e872a0SLloyd Pique 
522*84e872a0SLloyd Pique 	test_set_timeout(2);
523*84e872a0SLloyd Pique 
524*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_queue_roundtrip);
525*84e872a0SLloyd Pique 	display_run(d);
526*84e872a0SLloyd Pique 
527*84e872a0SLloyd Pique 	display_destroy(d);
528*84e872a0SLloyd Pique }
529*84e872a0SLloyd Pique 
TEST(queue_set_queue_proxy_wrapper)530*84e872a0SLloyd Pique TEST(queue_set_queue_proxy_wrapper)
531*84e872a0SLloyd Pique {
532*84e872a0SLloyd Pique 	struct display *d = display_create();
533*84e872a0SLloyd Pique 
534*84e872a0SLloyd Pique 	test_set_timeout(2);
535*84e872a0SLloyd Pique 
536*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_queue_proxy_wrapper);
537*84e872a0SLloyd Pique 	display_run(d);
538*84e872a0SLloyd Pique 
539*84e872a0SLloyd Pique 	display_destroy(d);
540*84e872a0SLloyd Pique }
541*84e872a0SLloyd Pique 
TEST(queue_set_queue_race)542*84e872a0SLloyd Pique TEST(queue_set_queue_race)
543*84e872a0SLloyd Pique {
544*84e872a0SLloyd Pique 	struct display *d = display_create();
545*84e872a0SLloyd Pique 
546*84e872a0SLloyd Pique 	test_set_timeout(2);
547*84e872a0SLloyd Pique 
548*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_queue_set_queue_race);
549*84e872a0SLloyd Pique 	display_run(d);
550*84e872a0SLloyd Pique 
551*84e872a0SLloyd Pique 	display_destroy(d);
552*84e872a0SLloyd Pique }
553*84e872a0SLloyd Pique 
TEST(queue_destroy_with_attached_proxies)554*84e872a0SLloyd Pique TEST(queue_destroy_with_attached_proxies)
555*84e872a0SLloyd Pique {
556*84e872a0SLloyd Pique 	struct display *d = display_create();
557*84e872a0SLloyd Pique 
558*84e872a0SLloyd Pique 	test_set_timeout(2);
559*84e872a0SLloyd Pique 
560*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_queue_destroy_with_attached_proxies);
561*84e872a0SLloyd Pique 	display_run(d);
562*84e872a0SLloyd Pique 
563*84e872a0SLloyd Pique 	display_destroy(d);
564*84e872a0SLloyd Pique }
565*84e872a0SLloyd Pique 
TEST(queue_proxy_event_to_destroyed_queue)566*84e872a0SLloyd Pique TEST(queue_proxy_event_to_destroyed_queue)
567*84e872a0SLloyd Pique {
568*84e872a0SLloyd Pique 	struct display *d = display_create();
569*84e872a0SLloyd Pique 	struct client_info *ci;
570*84e872a0SLloyd Pique 	char *client_log;
571*84e872a0SLloyd Pique 	size_t client_log_len;
572*84e872a0SLloyd Pique 
573*84e872a0SLloyd Pique 	test_set_timeout(2);
574*84e872a0SLloyd Pique 
575*84e872a0SLloyd Pique 	ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue);
576*84e872a0SLloyd Pique 	display_run(d);
577*84e872a0SLloyd Pique 
578*84e872a0SLloyd Pique 	/* Check that the final line in the log mentions the expected reason
579*84e872a0SLloyd Pique 	 * for the abort. */
580*84e872a0SLloyd Pique 	client_log = map_file(ci->log_fd, &client_log_len);
581*84e872a0SLloyd Pique 	assert(!strcmp(last_line_of(client_log),
582*84e872a0SLloyd Pique 		       "Tried to add event to destroyed queue\n"));
583*84e872a0SLloyd Pique 	munmap(client_log, client_log_len);
584*84e872a0SLloyd Pique 
585*84e872a0SLloyd Pique 	/* Check that the client aborted. */
586*84e872a0SLloyd Pique 	display_destroy_expect_signal(d, SIGABRT);
587*84e872a0SLloyd Pique }
588*84e872a0SLloyd Pique 
TEST(queue_destroy_default_with_attached_proxies)589*84e872a0SLloyd Pique TEST(queue_destroy_default_with_attached_proxies)
590*84e872a0SLloyd Pique {
591*84e872a0SLloyd Pique 	struct display *d = display_create();
592*84e872a0SLloyd Pique 
593*84e872a0SLloyd Pique 	test_set_timeout(2);
594*84e872a0SLloyd Pique 
595*84e872a0SLloyd Pique 	client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies);
596*84e872a0SLloyd Pique 	display_run(d);
597*84e872a0SLloyd Pique 
598*84e872a0SLloyd Pique 	display_destroy(d);
599*84e872a0SLloyd Pique }
600