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, ®istry_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