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