1*84e872a0SLloyd Pique /*
2*84e872a0SLloyd Pique * Copyright © 2012 Intel Corporation
3*84e872a0SLloyd Pique * Copyright © 2013 Jason Ekstrand
4*84e872a0SLloyd Pique *
5*84e872a0SLloyd Pique * Permission is hereby granted, free of charge, to any person obtaining
6*84e872a0SLloyd Pique * a copy of this software and associated documentation files (the
7*84e872a0SLloyd Pique * "Software"), to deal in the Software without restriction, including
8*84e872a0SLloyd Pique * without limitation the rights to use, copy, modify, merge, publish,
9*84e872a0SLloyd Pique * distribute, sublicense, and/or sell copies of the Software, and to
10*84e872a0SLloyd Pique * permit persons to whom the Software is furnished to do so, subject to
11*84e872a0SLloyd Pique * the following conditions:
12*84e872a0SLloyd Pique *
13*84e872a0SLloyd Pique * The above copyright notice and this permission notice (including the
14*84e872a0SLloyd Pique * next paragraph) shall be included in all copies or substantial
15*84e872a0SLloyd Pique * portions of the Software.
16*84e872a0SLloyd Pique *
17*84e872a0SLloyd Pique * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18*84e872a0SLloyd Pique * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*84e872a0SLloyd Pique * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20*84e872a0SLloyd Pique * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21*84e872a0SLloyd Pique * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22*84e872a0SLloyd Pique * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23*84e872a0SLloyd Pique * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24*84e872a0SLloyd Pique * SOFTWARE.
25*84e872a0SLloyd Pique */
26*84e872a0SLloyd Pique
27*84e872a0SLloyd Pique #define _GNU_SOURCE
28*84e872a0SLloyd Pique #include <stdbool.h>
29*84e872a0SLloyd Pique #include <stdio.h>
30*84e872a0SLloyd Pique #include <stdlib.h>
31*84e872a0SLloyd Pique #include <stdarg.h>
32*84e872a0SLloyd Pique #include <stdint.h>
33*84e872a0SLloyd Pique #include <string.h>
34*84e872a0SLloyd Pique #include <assert.h>
35*84e872a0SLloyd Pique #include <sys/socket.h>
36*84e872a0SLloyd Pique #include <unistd.h>
37*84e872a0SLloyd Pique #include <errno.h>
38*84e872a0SLloyd Pique #include <sys/types.h>
39*84e872a0SLloyd Pique #include <sys/stat.h>
40*84e872a0SLloyd Pique #include <sys/mman.h>
41*84e872a0SLloyd Pique
42*84e872a0SLloyd Pique #include <pthread.h>
43*84e872a0SLloyd Pique #include <poll.h>
44*84e872a0SLloyd Pique
45*84e872a0SLloyd Pique #include "wayland-private.h"
46*84e872a0SLloyd Pique #include "wayland-server.h"
47*84e872a0SLloyd Pique #include "wayland-client.h"
48*84e872a0SLloyd Pique #include "test-runner.h"
49*84e872a0SLloyd Pique #include "test-compositor.h"
50*84e872a0SLloyd Pique
51*84e872a0SLloyd Pique #include "tests-server-protocol.h"
52*84e872a0SLloyd Pique #include "tests-client-protocol.h"
53*84e872a0SLloyd Pique
54*84e872a0SLloyd Pique struct display_destroy_listener {
55*84e872a0SLloyd Pique struct wl_listener listener;
56*84e872a0SLloyd Pique int done;
57*84e872a0SLloyd Pique };
58*84e872a0SLloyd Pique
59*84e872a0SLloyd Pique static void
display_destroy_notify(struct wl_listener * l,void * data)60*84e872a0SLloyd Pique display_destroy_notify(struct wl_listener *l, void *data)
61*84e872a0SLloyd Pique {
62*84e872a0SLloyd Pique struct display_destroy_listener *listener;
63*84e872a0SLloyd Pique
64*84e872a0SLloyd Pique listener = wl_container_of(l, listener, listener);
65*84e872a0SLloyd Pique listener->done = 1;
66*84e872a0SLloyd Pique }
67*84e872a0SLloyd Pique
TEST(display_destroy_listener)68*84e872a0SLloyd Pique TEST(display_destroy_listener)
69*84e872a0SLloyd Pique {
70*84e872a0SLloyd Pique struct wl_display *display;
71*84e872a0SLloyd Pique struct display_destroy_listener a, b;
72*84e872a0SLloyd Pique
73*84e872a0SLloyd Pique display = wl_display_create();
74*84e872a0SLloyd Pique assert(display);
75*84e872a0SLloyd Pique
76*84e872a0SLloyd Pique a.listener.notify = &display_destroy_notify;
77*84e872a0SLloyd Pique a.done = 0;
78*84e872a0SLloyd Pique wl_display_add_destroy_listener(display, &a.listener);
79*84e872a0SLloyd Pique
80*84e872a0SLloyd Pique assert(wl_display_get_destroy_listener(display, display_destroy_notify) ==
81*84e872a0SLloyd Pique &a.listener);
82*84e872a0SLloyd Pique
83*84e872a0SLloyd Pique b.listener.notify = display_destroy_notify;
84*84e872a0SLloyd Pique b.done = 0;
85*84e872a0SLloyd Pique wl_display_add_destroy_listener(display, &b.listener);
86*84e872a0SLloyd Pique
87*84e872a0SLloyd Pique wl_list_remove(&a.listener.link);
88*84e872a0SLloyd Pique
89*84e872a0SLloyd Pique wl_display_destroy(display);
90*84e872a0SLloyd Pique
91*84e872a0SLloyd Pique assert(!a.done);
92*84e872a0SLloyd Pique assert(b.done);
93*84e872a0SLloyd Pique }
94*84e872a0SLloyd Pique
95*84e872a0SLloyd Pique /* Fake 'client' which does not use wl_display_connect, and thus leaves the
96*84e872a0SLloyd Pique * file descriptor passed through WAYLAND_SOCKET intact. This should not
97*84e872a0SLloyd Pique * trigger an assertion in the leak check. */
98*84e872a0SLloyd Pique static void
empty_client(void)99*84e872a0SLloyd Pique empty_client(void)
100*84e872a0SLloyd Pique {
101*84e872a0SLloyd Pique return;
102*84e872a0SLloyd Pique }
103*84e872a0SLloyd Pique
TEST(tc_leaks_tests)104*84e872a0SLloyd Pique TEST(tc_leaks_tests)
105*84e872a0SLloyd Pique {
106*84e872a0SLloyd Pique struct display *d = display_create();
107*84e872a0SLloyd Pique client_create_noarg(d, empty_client);
108*84e872a0SLloyd Pique display_run(d);
109*84e872a0SLloyd Pique display_destroy(d);
110*84e872a0SLloyd Pique }
111*84e872a0SLloyd Pique
112*84e872a0SLloyd Pique /* This is how pre proxy-version registry binds worked,
113*84e872a0SLloyd Pique * this should create a proxy that shares the display's
114*84e872a0SLloyd Pique * version number: 0 */
115*84e872a0SLloyd Pique static void *
old_registry_bind(struct wl_registry * wl_registry,uint32_t name,const struct wl_interface * interface,uint32_t version)116*84e872a0SLloyd Pique old_registry_bind(struct wl_registry *wl_registry,
117*84e872a0SLloyd Pique uint32_t name,
118*84e872a0SLloyd Pique const struct wl_interface *interface,
119*84e872a0SLloyd Pique uint32_t version)
120*84e872a0SLloyd Pique {
121*84e872a0SLloyd Pique struct wl_proxy *id;
122*84e872a0SLloyd Pique
123*84e872a0SLloyd Pique id = wl_proxy_marshal_constructor(
124*84e872a0SLloyd Pique (struct wl_proxy *) wl_registry, WL_REGISTRY_BIND,
125*84e872a0SLloyd Pique interface, name, interface->name, version, NULL);
126*84e872a0SLloyd Pique
127*84e872a0SLloyd Pique return (void *) id;
128*84e872a0SLloyd Pique }
129*84e872a0SLloyd Pique
130*84e872a0SLloyd Pique struct handler_info {
131*84e872a0SLloyd Pique struct wl_seat *seat;
132*84e872a0SLloyd Pique uint32_t bind_version;
133*84e872a0SLloyd Pique bool use_unversioned;
134*84e872a0SLloyd Pique };
135*84e872a0SLloyd Pique
136*84e872a0SLloyd Pique static void
registry_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)137*84e872a0SLloyd Pique registry_handle_globals(void *data, struct wl_registry *registry,
138*84e872a0SLloyd Pique uint32_t id, const char *intf, uint32_t ver)
139*84e872a0SLloyd Pique {
140*84e872a0SLloyd Pique struct handler_info *hi = data;
141*84e872a0SLloyd Pique
142*84e872a0SLloyd Pique /* This is only for the proxy version test */
143*84e872a0SLloyd Pique if (hi->bind_version)
144*84e872a0SLloyd Pique ver = hi->bind_version;
145*84e872a0SLloyd Pique
146*84e872a0SLloyd Pique if (strcmp(intf, "wl_seat") == 0) {
147*84e872a0SLloyd Pique if (hi->use_unversioned)
148*84e872a0SLloyd Pique hi->seat = old_registry_bind(registry, id,
149*84e872a0SLloyd Pique &wl_seat_interface, ver);
150*84e872a0SLloyd Pique else
151*84e872a0SLloyd Pique hi->seat = wl_registry_bind(registry, id,
152*84e872a0SLloyd Pique &wl_seat_interface, ver);
153*84e872a0SLloyd Pique assert(hi->seat);
154*84e872a0SLloyd Pique }
155*84e872a0SLloyd Pique }
156*84e872a0SLloyd Pique
157*84e872a0SLloyd Pique static const struct wl_registry_listener registry_listener = {
158*84e872a0SLloyd Pique registry_handle_globals,
159*84e872a0SLloyd Pique NULL
160*84e872a0SLloyd Pique };
161*84e872a0SLloyd Pique
162*84e872a0SLloyd Pique static struct wl_seat *
client_get_seat_with_info(struct client * c,struct handler_info * hi)163*84e872a0SLloyd Pique client_get_seat_with_info(struct client *c, struct handler_info *hi)
164*84e872a0SLloyd Pique {
165*84e872a0SLloyd Pique struct wl_registry *reg = wl_display_get_registry(c->wl_display);
166*84e872a0SLloyd Pique assert(reg);
167*84e872a0SLloyd Pique
168*84e872a0SLloyd Pique assert(hi);
169*84e872a0SLloyd Pique hi->seat = NULL;
170*84e872a0SLloyd Pique wl_registry_add_listener(reg, ®istry_listener, hi);
171*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
172*84e872a0SLloyd Pique assert(hi->seat);
173*84e872a0SLloyd Pique
174*84e872a0SLloyd Pique wl_registry_destroy(reg);
175*84e872a0SLloyd Pique
176*84e872a0SLloyd Pique return hi->seat;
177*84e872a0SLloyd Pique }
178*84e872a0SLloyd Pique
179*84e872a0SLloyd Pique static struct wl_seat *
client_get_seat(struct client * c)180*84e872a0SLloyd Pique client_get_seat(struct client *c)
181*84e872a0SLloyd Pique {
182*84e872a0SLloyd Pique struct handler_info hi;
183*84e872a0SLloyd Pique
184*84e872a0SLloyd Pique hi.use_unversioned = false;
185*84e872a0SLloyd Pique hi.bind_version = 0;
186*84e872a0SLloyd Pique
187*84e872a0SLloyd Pique return client_get_seat_with_info(c, &hi);
188*84e872a0SLloyd Pique }
189*84e872a0SLloyd Pique
190*84e872a0SLloyd Pique static void
check_pending_error(struct client * c,struct wl_proxy * proxy)191*84e872a0SLloyd Pique check_pending_error(struct client *c, struct wl_proxy *proxy)
192*84e872a0SLloyd Pique {
193*84e872a0SLloyd Pique uint32_t ec, id;
194*84e872a0SLloyd Pique int err;
195*84e872a0SLloyd Pique const struct wl_interface *intf;
196*84e872a0SLloyd Pique
197*84e872a0SLloyd Pique err = wl_display_get_error(c->wl_display);
198*84e872a0SLloyd Pique assert(err == EPROTO);
199*84e872a0SLloyd Pique
200*84e872a0SLloyd Pique ec = wl_display_get_protocol_error(c->wl_display, &intf, &id);
201*84e872a0SLloyd Pique assert(ec == 23);
202*84e872a0SLloyd Pique assert(intf == &wl_seat_interface);
203*84e872a0SLloyd Pique assert(id == wl_proxy_get_id(proxy));
204*84e872a0SLloyd Pique }
205*84e872a0SLloyd Pique
206*84e872a0SLloyd Pique static void
check_for_error(struct client * c,struct wl_proxy * proxy)207*84e872a0SLloyd Pique check_for_error(struct client *c, struct wl_proxy *proxy)
208*84e872a0SLloyd Pique {
209*84e872a0SLloyd Pique /* client should be disconnected */
210*84e872a0SLloyd Pique assert(wl_display_roundtrip(c->wl_display) == -1);
211*84e872a0SLloyd Pique
212*84e872a0SLloyd Pique check_pending_error(c, proxy);
213*84e872a0SLloyd Pique }
214*84e872a0SLloyd Pique
215*84e872a0SLloyd Pique static struct client_info *
find_client_info(struct display * d,struct wl_client * client)216*84e872a0SLloyd Pique find_client_info(struct display *d, struct wl_client *client)
217*84e872a0SLloyd Pique {
218*84e872a0SLloyd Pique struct client_info *ci;
219*84e872a0SLloyd Pique
220*84e872a0SLloyd Pique wl_list_for_each(ci, &d->clients, link) {
221*84e872a0SLloyd Pique if (ci->wl_client == client)
222*84e872a0SLloyd Pique return ci;
223*84e872a0SLloyd Pique }
224*84e872a0SLloyd Pique
225*84e872a0SLloyd Pique return NULL;
226*84e872a0SLloyd Pique }
227*84e872a0SLloyd Pique
228*84e872a0SLloyd Pique static void
bind_seat(struct wl_client * client,void * data,uint32_t vers,uint32_t id)229*84e872a0SLloyd Pique bind_seat(struct wl_client *client, void *data,
230*84e872a0SLloyd Pique uint32_t vers, uint32_t id)
231*84e872a0SLloyd Pique {
232*84e872a0SLloyd Pique struct display *d = data;
233*84e872a0SLloyd Pique struct client_info *ci;
234*84e872a0SLloyd Pique struct wl_resource *res;
235*84e872a0SLloyd Pique
236*84e872a0SLloyd Pique ci = find_client_info(d, client);
237*84e872a0SLloyd Pique assert(ci);
238*84e872a0SLloyd Pique
239*84e872a0SLloyd Pique res = wl_resource_create(client, &wl_seat_interface, vers, id);
240*84e872a0SLloyd Pique assert(res);
241*84e872a0SLloyd Pique
242*84e872a0SLloyd Pique /* save the resource as client's info data,
243*84e872a0SLloyd Pique * so that we can use it later */
244*84e872a0SLloyd Pique ci->data = res;
245*84e872a0SLloyd Pique }
246*84e872a0SLloyd Pique
247*84e872a0SLloyd Pique static void
client_disconnect_nocheck(struct client * c)248*84e872a0SLloyd Pique client_disconnect_nocheck(struct client *c)
249*84e872a0SLloyd Pique {
250*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) c->tc);
251*84e872a0SLloyd Pique wl_display_disconnect(c->wl_display);
252*84e872a0SLloyd Pique free(c);
253*84e872a0SLloyd Pique }
254*84e872a0SLloyd Pique
255*84e872a0SLloyd Pique static void
post_error_main(void)256*84e872a0SLloyd Pique post_error_main(void)
257*84e872a0SLloyd Pique {
258*84e872a0SLloyd Pique struct client *c = client_connect();
259*84e872a0SLloyd Pique struct wl_seat *seat = client_get_seat(c);
260*84e872a0SLloyd Pique
261*84e872a0SLloyd Pique /* stop display so that it can post the error.
262*84e872a0SLloyd Pique * The function should return -1, because of the posted error */
263*84e872a0SLloyd Pique assert(stop_display(c, 1) == -1);
264*84e872a0SLloyd Pique
265*84e872a0SLloyd Pique /* display should have posted error, check it! */
266*84e872a0SLloyd Pique check_for_error(c, (struct wl_proxy *) seat);
267*84e872a0SLloyd Pique
268*84e872a0SLloyd Pique /* don't call client_disconnect(c), because then the test would be
269*84e872a0SLloyd Pique * aborted due to checks for error in this function */
270*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
271*84e872a0SLloyd Pique client_disconnect_nocheck(c);
272*84e872a0SLloyd Pique }
273*84e872a0SLloyd Pique
TEST(post_error_to_one_client)274*84e872a0SLloyd Pique TEST(post_error_to_one_client)
275*84e872a0SLloyd Pique {
276*84e872a0SLloyd Pique struct display *d = display_create();
277*84e872a0SLloyd Pique struct client_info *cl;
278*84e872a0SLloyd Pique
279*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
280*84e872a0SLloyd Pique 1, d, bind_seat);
281*84e872a0SLloyd Pique
282*84e872a0SLloyd Pique cl = client_create_noarg(d, post_error_main);
283*84e872a0SLloyd Pique display_run(d);
284*84e872a0SLloyd Pique
285*84e872a0SLloyd Pique /* the display was stopped by client, so it can
286*84e872a0SLloyd Pique * proceed in the code and post an error */
287*84e872a0SLloyd Pique assert(cl->data);
288*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
289*84e872a0SLloyd Pique 23, "Dummy error");
290*84e872a0SLloyd Pique
291*84e872a0SLloyd Pique /* this one should be ignored */
292*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
293*84e872a0SLloyd Pique 21, "Dummy error (ignore)");
294*84e872a0SLloyd Pique
295*84e872a0SLloyd Pique display_resume(d);
296*84e872a0SLloyd Pique display_destroy(d);
297*84e872a0SLloyd Pique }
298*84e872a0SLloyd Pique
299*84e872a0SLloyd Pique static void
post_error_main2(void)300*84e872a0SLloyd Pique post_error_main2(void)
301*84e872a0SLloyd Pique {
302*84e872a0SLloyd Pique struct client *c = client_connect();
303*84e872a0SLloyd Pique struct wl_seat *seat = client_get_seat(c);
304*84e872a0SLloyd Pique
305*84e872a0SLloyd Pique /* the error should not be posted for this client */
306*84e872a0SLloyd Pique assert(stop_display(c, 2) >= 0);
307*84e872a0SLloyd Pique
308*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
309*84e872a0SLloyd Pique client_disconnect(c);
310*84e872a0SLloyd Pique }
311*84e872a0SLloyd Pique
312*84e872a0SLloyd Pique static void
post_error_main3(void)313*84e872a0SLloyd Pique post_error_main3(void)
314*84e872a0SLloyd Pique {
315*84e872a0SLloyd Pique struct client *c = client_connect();
316*84e872a0SLloyd Pique struct wl_seat *seat = client_get_seat(c);
317*84e872a0SLloyd Pique
318*84e872a0SLloyd Pique assert(stop_display(c, 2) == -1);
319*84e872a0SLloyd Pique check_for_error(c, (struct wl_proxy *) seat);
320*84e872a0SLloyd Pique
321*84e872a0SLloyd Pique /* don't call client_disconnect(c), because then the test would be
322*84e872a0SLloyd Pique * aborted due to checks for error in this function */
323*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
324*84e872a0SLloyd Pique client_disconnect_nocheck(c);
325*84e872a0SLloyd Pique }
326*84e872a0SLloyd Pique
327*84e872a0SLloyd Pique /* all the testcases could be in one TEST, but splitting it
328*84e872a0SLloyd Pique * apart is better for debugging when the test fails */
TEST(post_error_to_one_from_two_clients)329*84e872a0SLloyd Pique TEST(post_error_to_one_from_two_clients)
330*84e872a0SLloyd Pique {
331*84e872a0SLloyd Pique struct display *d = display_create();
332*84e872a0SLloyd Pique struct client_info *cl;
333*84e872a0SLloyd Pique
334*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
335*84e872a0SLloyd Pique 1, d, bind_seat);
336*84e872a0SLloyd Pique
337*84e872a0SLloyd Pique client_create_noarg(d, post_error_main2);
338*84e872a0SLloyd Pique cl = client_create_noarg(d, post_error_main3);
339*84e872a0SLloyd Pique display_run(d);
340*84e872a0SLloyd Pique
341*84e872a0SLloyd Pique /* post error only to the second client */
342*84e872a0SLloyd Pique assert(cl->data);
343*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
344*84e872a0SLloyd Pique 23, "Dummy error");
345*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
346*84e872a0SLloyd Pique 21, "Dummy error (ignore)");
347*84e872a0SLloyd Pique
348*84e872a0SLloyd Pique display_resume(d);
349*84e872a0SLloyd Pique display_destroy(d);
350*84e872a0SLloyd Pique }
351*84e872a0SLloyd Pique
352*84e872a0SLloyd Pique /* all the testcases could be in one TEST, but splitting it
353*84e872a0SLloyd Pique * apart is better for debugging when the test fails */
TEST(post_error_to_two_clients)354*84e872a0SLloyd Pique TEST(post_error_to_two_clients)
355*84e872a0SLloyd Pique {
356*84e872a0SLloyd Pique struct display *d = display_create();
357*84e872a0SLloyd Pique struct client_info *cl, *cl2;
358*84e872a0SLloyd Pique
359*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
360*84e872a0SLloyd Pique 1, d, bind_seat);
361*84e872a0SLloyd Pique
362*84e872a0SLloyd Pique cl = client_create_noarg(d, post_error_main3);
363*84e872a0SLloyd Pique cl2 = client_create_noarg(d, post_error_main3);
364*84e872a0SLloyd Pique
365*84e872a0SLloyd Pique display_run(d);
366*84e872a0SLloyd Pique
367*84e872a0SLloyd Pique /* Try to send the error to both clients */
368*84e872a0SLloyd Pique assert(cl->data && cl2->data);
369*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
370*84e872a0SLloyd Pique 23, "Dummy error");
371*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
372*84e872a0SLloyd Pique 21, "Dummy error (ignore)");
373*84e872a0SLloyd Pique
374*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl2->data,
375*84e872a0SLloyd Pique 23, "Dummy error");
376*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl2->data,
377*84e872a0SLloyd Pique 21, "Dummy error (ignore)");
378*84e872a0SLloyd Pique
379*84e872a0SLloyd Pique display_resume(d);
380*84e872a0SLloyd Pique display_destroy(d);
381*84e872a0SLloyd Pique }
382*84e872a0SLloyd Pique
383*84e872a0SLloyd Pique static void
post_nomem_main(void)384*84e872a0SLloyd Pique post_nomem_main(void)
385*84e872a0SLloyd Pique {
386*84e872a0SLloyd Pique struct client *c = client_connect();
387*84e872a0SLloyd Pique struct wl_seat *seat = client_get_seat(c);
388*84e872a0SLloyd Pique
389*84e872a0SLloyd Pique assert(stop_display(c, 1) == -1);
390*84e872a0SLloyd Pique assert(wl_display_get_error(c->wl_display) == ENOMEM);
391*84e872a0SLloyd Pique
392*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
393*84e872a0SLloyd Pique client_disconnect_nocheck(c);
394*84e872a0SLloyd Pique }
395*84e872a0SLloyd Pique
TEST(post_nomem_tst)396*84e872a0SLloyd Pique TEST(post_nomem_tst)
397*84e872a0SLloyd Pique {
398*84e872a0SLloyd Pique struct display *d = display_create();
399*84e872a0SLloyd Pique struct client_info *cl;
400*84e872a0SLloyd Pique
401*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
402*84e872a0SLloyd Pique 1, d, bind_seat);
403*84e872a0SLloyd Pique
404*84e872a0SLloyd Pique cl = client_create_noarg(d, post_nomem_main);
405*84e872a0SLloyd Pique display_run(d);
406*84e872a0SLloyd Pique
407*84e872a0SLloyd Pique assert(cl->data);
408*84e872a0SLloyd Pique wl_resource_post_no_memory((struct wl_resource *) cl->data);
409*84e872a0SLloyd Pique display_resume(d);
410*84e872a0SLloyd Pique
411*84e872a0SLloyd Pique /* first client terminated. Run it again,
412*84e872a0SLloyd Pique * but post no memory to client */
413*84e872a0SLloyd Pique cl = client_create_noarg(d, post_nomem_main);
414*84e872a0SLloyd Pique display_run(d);
415*84e872a0SLloyd Pique
416*84e872a0SLloyd Pique assert(cl->data);
417*84e872a0SLloyd Pique wl_client_post_no_memory(cl->wl_client);
418*84e872a0SLloyd Pique display_resume(d);
419*84e872a0SLloyd Pique
420*84e872a0SLloyd Pique display_destroy(d);
421*84e872a0SLloyd Pique }
422*84e872a0SLloyd Pique
423*84e872a0SLloyd Pique static void
post_implementation_error_main(void)424*84e872a0SLloyd Pique post_implementation_error_main(void)
425*84e872a0SLloyd Pique {
426*84e872a0SLloyd Pique struct client *c = client_connect();
427*84e872a0SLloyd Pique struct wl_seat *seat = client_get_seat(c);
428*84e872a0SLloyd Pique uint32_t object_id, protocol_error;
429*84e872a0SLloyd Pique const struct wl_interface *interface;
430*84e872a0SLloyd Pique
431*84e872a0SLloyd Pique assert(stop_display(c, 1) == -1);
432*84e872a0SLloyd Pique int err = wl_display_get_error(c->wl_display);
433*84e872a0SLloyd Pique fprintf(stderr, "Err is %i\n", err);
434*84e872a0SLloyd Pique assert(err == EPROTO);
435*84e872a0SLloyd Pique protocol_error = wl_display_get_protocol_error(c->wl_display,
436*84e872a0SLloyd Pique &interface,
437*84e872a0SLloyd Pique &object_id);
438*84e872a0SLloyd Pique assert(protocol_error == WL_DISPLAY_ERROR_IMPLEMENTATION);
439*84e872a0SLloyd Pique assert(interface == &wl_display_interface);
440*84e872a0SLloyd Pique
441*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
442*84e872a0SLloyd Pique client_disconnect_nocheck(c);
443*84e872a0SLloyd Pique }
444*84e872a0SLloyd Pique
TEST(post_internal_error_tst)445*84e872a0SLloyd Pique TEST(post_internal_error_tst)
446*84e872a0SLloyd Pique {
447*84e872a0SLloyd Pique struct display *d = display_create();
448*84e872a0SLloyd Pique struct client_info *cl;
449*84e872a0SLloyd Pique
450*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
451*84e872a0SLloyd Pique 1, d, bind_seat);
452*84e872a0SLloyd Pique
453*84e872a0SLloyd Pique cl = client_create_noarg(d, post_implementation_error_main);
454*84e872a0SLloyd Pique display_run(d);
455*84e872a0SLloyd Pique
456*84e872a0SLloyd Pique wl_client_post_implementation_error(cl->wl_client, "Error %i", 20);
457*84e872a0SLloyd Pique
458*84e872a0SLloyd Pique display_resume(d);
459*84e872a0SLloyd Pique
460*84e872a0SLloyd Pique display_destroy(d);
461*84e872a0SLloyd Pique }
462*84e872a0SLloyd Pique
463*84e872a0SLloyd Pique static void
register_reading(struct wl_display * display)464*84e872a0SLloyd Pique register_reading(struct wl_display *display)
465*84e872a0SLloyd Pique {
466*84e872a0SLloyd Pique while(wl_display_prepare_read(display) != 0 && errno == EAGAIN)
467*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(display) >= 0);
468*84e872a0SLloyd Pique assert(wl_display_flush(display) >= 0);
469*84e872a0SLloyd Pique }
470*84e872a0SLloyd Pique
471*84e872a0SLloyd Pique /* create thread that will call prepare+read so that
472*84e872a0SLloyd Pique * it will block */
473*84e872a0SLloyd Pique static pthread_t
create_thread(struct client * c,void * (* func)(void *))474*84e872a0SLloyd Pique create_thread(struct client *c, void *(*func)(void*))
475*84e872a0SLloyd Pique {
476*84e872a0SLloyd Pique pthread_t thread;
477*84e872a0SLloyd Pique
478*84e872a0SLloyd Pique c->display_stopped = 0;
479*84e872a0SLloyd Pique /* func must set display->stopped to 1 before sleeping */
480*84e872a0SLloyd Pique assert(pthread_create(&thread, NULL, func, c) == 0);
481*84e872a0SLloyd Pique
482*84e872a0SLloyd Pique /* make sure the thread is sleeping. It's a little bit racy
483*84e872a0SLloyd Pique * (setting display_stopped to 1 and calling wl_display_read_events)
484*84e872a0SLloyd Pique * so call usleep once again after the loop ends - it should
485*84e872a0SLloyd Pique * be sufficient... */
486*84e872a0SLloyd Pique while (c->display_stopped == 0)
487*84e872a0SLloyd Pique test_usleep(500);
488*84e872a0SLloyd Pique test_usleep(10000);
489*84e872a0SLloyd Pique
490*84e872a0SLloyd Pique return thread;
491*84e872a0SLloyd Pique }
492*84e872a0SLloyd Pique
493*84e872a0SLloyd Pique static void *
thread_read_error(void * data)494*84e872a0SLloyd Pique thread_read_error(void *data)
495*84e872a0SLloyd Pique {
496*84e872a0SLloyd Pique struct client *c = data;
497*84e872a0SLloyd Pique
498*84e872a0SLloyd Pique register_reading(c->wl_display);
499*84e872a0SLloyd Pique
500*84e872a0SLloyd Pique /*
501*84e872a0SLloyd Pique * Calling the read right now will block this thread
502*84e872a0SLloyd Pique * until the other thread will read the data.
503*84e872a0SLloyd Pique * However, after invoking an error, this
504*84e872a0SLloyd Pique * thread should be woken up or it will block indefinitely.
505*84e872a0SLloyd Pique */
506*84e872a0SLloyd Pique c->display_stopped = 1;
507*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == -1);
508*84e872a0SLloyd Pique
509*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) == -1);
510*84e872a0SLloyd Pique assert(wl_display_get_error(c->wl_display));
511*84e872a0SLloyd Pique
512*84e872a0SLloyd Pique pthread_exit(NULL);
513*84e872a0SLloyd Pique }
514*84e872a0SLloyd Pique
515*84e872a0SLloyd Pique /* test posting an error in multi-threaded environment. */
516*84e872a0SLloyd Pique static void
threading_post_err(void)517*84e872a0SLloyd Pique threading_post_err(void)
518*84e872a0SLloyd Pique {
519*84e872a0SLloyd Pique DISABLE_LEAK_CHECKS;
520*84e872a0SLloyd Pique
521*84e872a0SLloyd Pique struct client *c = client_connect();
522*84e872a0SLloyd Pique pthread_t thread;
523*84e872a0SLloyd Pique
524*84e872a0SLloyd Pique /* register read intention */
525*84e872a0SLloyd Pique register_reading(c->wl_display);
526*84e872a0SLloyd Pique
527*84e872a0SLloyd Pique /* use this var as an indicator that thread is sleeping */
528*84e872a0SLloyd Pique c->display_stopped = 0;
529*84e872a0SLloyd Pique
530*84e872a0SLloyd Pique /* create new thread that will register its intention too */
531*84e872a0SLloyd Pique thread = create_thread(c, thread_read_error);
532*84e872a0SLloyd Pique
533*84e872a0SLloyd Pique /* so now we have sleeping thread waiting for a pthread_cond signal.
534*84e872a0SLloyd Pique * The main thread must call wl_display_read_events().
535*84e872a0SLloyd Pique * If this call fails, then it won't call broadcast at the
536*84e872a0SLloyd Pique * end of the function and the sleeping thread will block indefinitely.
537*84e872a0SLloyd Pique * Make the call fail and watch if libwayland will unblock the thread! */
538*84e872a0SLloyd Pique
539*84e872a0SLloyd Pique /* create error on fd, so that wl_display_read_events will fail.
540*84e872a0SLloyd Pique * The same can happen when server hangs up */
541*84e872a0SLloyd Pique close(wl_display_get_fd(c->wl_display));
542*84e872a0SLloyd Pique /* this read events will fail and will
543*84e872a0SLloyd Pique * post an error that should wake the sleeping thread
544*84e872a0SLloyd Pique * and dispatch the incoming events */
545*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == -1);
546*84e872a0SLloyd Pique
547*84e872a0SLloyd Pique /* kill test in 3 seconds. This should be enough time for the
548*84e872a0SLloyd Pique * thread to exit if it's not blocking. If everything is OK, than
549*84e872a0SLloyd Pique * the thread was woken up and the test will end before the SIGALRM */
550*84e872a0SLloyd Pique test_set_timeout(3);
551*84e872a0SLloyd Pique pthread_join(thread, NULL);
552*84e872a0SLloyd Pique
553*84e872a0SLloyd Pique client_disconnect_nocheck(c);
554*84e872a0SLloyd Pique }
555*84e872a0SLloyd Pique
TEST(threading_errors_tst)556*84e872a0SLloyd Pique TEST(threading_errors_tst)
557*84e872a0SLloyd Pique {
558*84e872a0SLloyd Pique struct display *d = display_create();
559*84e872a0SLloyd Pique
560*84e872a0SLloyd Pique client_create_noarg(d, threading_post_err);
561*84e872a0SLloyd Pique display_run(d);
562*84e872a0SLloyd Pique
563*84e872a0SLloyd Pique display_destroy(d);
564*84e872a0SLloyd Pique }
565*84e872a0SLloyd Pique
566*84e872a0SLloyd Pique static void *
thread_prepare_and_read(void * data)567*84e872a0SLloyd Pique thread_prepare_and_read(void *data)
568*84e872a0SLloyd Pique {
569*84e872a0SLloyd Pique struct client *c = data;
570*84e872a0SLloyd Pique
571*84e872a0SLloyd Pique register_reading(c->wl_display);
572*84e872a0SLloyd Pique
573*84e872a0SLloyd Pique c->display_stopped = 1;
574*84e872a0SLloyd Pique
575*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == 0);
576*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) == 0);
577*84e872a0SLloyd Pique
578*84e872a0SLloyd Pique pthread_exit(NULL);
579*84e872a0SLloyd Pique }
580*84e872a0SLloyd Pique
581*84e872a0SLloyd Pique /* test cancel read*/
582*84e872a0SLloyd Pique static void
threading_cancel_read(void)583*84e872a0SLloyd Pique threading_cancel_read(void)
584*84e872a0SLloyd Pique {
585*84e872a0SLloyd Pique DISABLE_LEAK_CHECKS;
586*84e872a0SLloyd Pique
587*84e872a0SLloyd Pique struct client *c = client_connect();
588*84e872a0SLloyd Pique pthread_t th1, th2, th3;
589*84e872a0SLloyd Pique
590*84e872a0SLloyd Pique register_reading(c->wl_display);
591*84e872a0SLloyd Pique
592*84e872a0SLloyd Pique th1 = create_thread(c, thread_prepare_and_read);
593*84e872a0SLloyd Pique th2 = create_thread(c, thread_prepare_and_read);
594*84e872a0SLloyd Pique th3 = create_thread(c, thread_prepare_and_read);
595*84e872a0SLloyd Pique
596*84e872a0SLloyd Pique /* all the threads are sleeping, waiting until read or cancel
597*84e872a0SLloyd Pique * is called. Cancel the read and let the threads proceed */
598*84e872a0SLloyd Pique wl_display_cancel_read(c->wl_display);
599*84e872a0SLloyd Pique
600*84e872a0SLloyd Pique /* kill test in 3 seconds. This should be enough time for the
601*84e872a0SLloyd Pique * thread to exit if it's not blocking. If everything is OK, than
602*84e872a0SLloyd Pique * the thread was woken up and the test will end before the SIGALRM */
603*84e872a0SLloyd Pique test_set_timeout(3);
604*84e872a0SLloyd Pique pthread_join(th1, NULL);
605*84e872a0SLloyd Pique pthread_join(th2, NULL);
606*84e872a0SLloyd Pique pthread_join(th3, NULL);
607*84e872a0SLloyd Pique
608*84e872a0SLloyd Pique client_disconnect(c);
609*84e872a0SLloyd Pique }
610*84e872a0SLloyd Pique
TEST(threading_cancel_read_tst)611*84e872a0SLloyd Pique TEST(threading_cancel_read_tst)
612*84e872a0SLloyd Pique {
613*84e872a0SLloyd Pique struct display *d = display_create();
614*84e872a0SLloyd Pique
615*84e872a0SLloyd Pique client_create_noarg(d, threading_cancel_read);
616*84e872a0SLloyd Pique display_run(d);
617*84e872a0SLloyd Pique
618*84e872a0SLloyd Pique display_destroy(d);
619*84e872a0SLloyd Pique }
620*84e872a0SLloyd Pique
621*84e872a0SLloyd Pique static void
threading_read_eagain(void)622*84e872a0SLloyd Pique threading_read_eagain(void)
623*84e872a0SLloyd Pique {
624*84e872a0SLloyd Pique DISABLE_LEAK_CHECKS;
625*84e872a0SLloyd Pique
626*84e872a0SLloyd Pique struct client *c = client_connect();
627*84e872a0SLloyd Pique pthread_t th1, th2, th3;
628*84e872a0SLloyd Pique
629*84e872a0SLloyd Pique register_reading(c->wl_display);
630*84e872a0SLloyd Pique
631*84e872a0SLloyd Pique th1 = create_thread(c, thread_prepare_and_read);
632*84e872a0SLloyd Pique th2 = create_thread(c, thread_prepare_and_read);
633*84e872a0SLloyd Pique th3 = create_thread(c, thread_prepare_and_read);
634*84e872a0SLloyd Pique
635*84e872a0SLloyd Pique /* All the threads are sleeping, waiting until read or cancel
636*84e872a0SLloyd Pique * is called. Since we have no data on socket waiting,
637*84e872a0SLloyd Pique * the wl_connection_read should end up with error and set errno
638*84e872a0SLloyd Pique * to EAGAIN. Check if the threads are woken up in this case. */
639*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == 0);
640*84e872a0SLloyd Pique /* errno should be still set to EAGAIN if wl_connection_read
641*84e872a0SLloyd Pique * set it - check if we're testing the right case */
642*84e872a0SLloyd Pique assert(errno == EAGAIN);
643*84e872a0SLloyd Pique
644*84e872a0SLloyd Pique test_set_timeout(3);
645*84e872a0SLloyd Pique pthread_join(th1, NULL);
646*84e872a0SLloyd Pique pthread_join(th2, NULL);
647*84e872a0SLloyd Pique pthread_join(th3, NULL);
648*84e872a0SLloyd Pique
649*84e872a0SLloyd Pique client_disconnect(c);
650*84e872a0SLloyd Pique }
651*84e872a0SLloyd Pique
TEST(threading_read_eagain_tst)652*84e872a0SLloyd Pique TEST(threading_read_eagain_tst)
653*84e872a0SLloyd Pique {
654*84e872a0SLloyd Pique struct display *d = display_create();
655*84e872a0SLloyd Pique client_create_noarg(d, threading_read_eagain);
656*84e872a0SLloyd Pique
657*84e872a0SLloyd Pique display_run(d);
658*84e872a0SLloyd Pique
659*84e872a0SLloyd Pique display_destroy(d);
660*84e872a0SLloyd Pique }
661*84e872a0SLloyd Pique
662*84e872a0SLloyd Pique static void *
thread_prepare_and_read2(void * data)663*84e872a0SLloyd Pique thread_prepare_and_read2(void *data)
664*84e872a0SLloyd Pique {
665*84e872a0SLloyd Pique struct client *c = data;
666*84e872a0SLloyd Pique
667*84e872a0SLloyd Pique while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
668*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) == -1);
669*84e872a0SLloyd Pique assert(wl_display_flush(c->wl_display) == -1);
670*84e872a0SLloyd Pique
671*84e872a0SLloyd Pique c->display_stopped = 1;
672*84e872a0SLloyd Pique
673*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == -1);
674*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) == -1);
675*84e872a0SLloyd Pique
676*84e872a0SLloyd Pique pthread_exit(NULL);
677*84e872a0SLloyd Pique }
678*84e872a0SLloyd Pique
679*84e872a0SLloyd Pique static void
threading_read_after_error(void)680*84e872a0SLloyd Pique threading_read_after_error(void)
681*84e872a0SLloyd Pique {
682*84e872a0SLloyd Pique DISABLE_LEAK_CHECKS;
683*84e872a0SLloyd Pique
684*84e872a0SLloyd Pique struct client *c = client_connect();
685*84e872a0SLloyd Pique pthread_t thread;
686*84e872a0SLloyd Pique
687*84e872a0SLloyd Pique /* create an error */
688*84e872a0SLloyd Pique close(wl_display_get_fd(c->wl_display));
689*84e872a0SLloyd Pique assert(wl_display_dispatch(c->wl_display) == -1);
690*84e872a0SLloyd Pique
691*84e872a0SLloyd Pique /* try to prepare for reading */
692*84e872a0SLloyd Pique while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
693*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) == -1);
694*84e872a0SLloyd Pique assert(wl_display_flush(c->wl_display) == -1);
695*84e872a0SLloyd Pique
696*84e872a0SLloyd Pique assert(pthread_create(&thread, NULL,
697*84e872a0SLloyd Pique thread_prepare_and_read2, c) == 0);
698*84e872a0SLloyd Pique
699*84e872a0SLloyd Pique /* make sure thread is sleeping */
700*84e872a0SLloyd Pique while (c->display_stopped == 0)
701*84e872a0SLloyd Pique test_usleep(500);
702*84e872a0SLloyd Pique test_usleep(10000);
703*84e872a0SLloyd Pique
704*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == -1);
705*84e872a0SLloyd Pique
706*84e872a0SLloyd Pique /* kill test in 3 seconds */
707*84e872a0SLloyd Pique test_set_timeout(3);
708*84e872a0SLloyd Pique pthread_join(thread, NULL);
709*84e872a0SLloyd Pique
710*84e872a0SLloyd Pique client_disconnect_nocheck(c);
711*84e872a0SLloyd Pique }
712*84e872a0SLloyd Pique
TEST(threading_read_after_error_tst)713*84e872a0SLloyd Pique TEST(threading_read_after_error_tst)
714*84e872a0SLloyd Pique {
715*84e872a0SLloyd Pique struct display *d = display_create();
716*84e872a0SLloyd Pique
717*84e872a0SLloyd Pique client_create_noarg(d, threading_read_after_error);
718*84e872a0SLloyd Pique display_run(d);
719*84e872a0SLloyd Pique
720*84e872a0SLloyd Pique display_destroy(d);
721*84e872a0SLloyd Pique }
722*84e872a0SLloyd Pique
723*84e872a0SLloyd Pique static void
wait_for_error_using_dispatch(struct client * c,struct wl_proxy * proxy)724*84e872a0SLloyd Pique wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy)
725*84e872a0SLloyd Pique {
726*84e872a0SLloyd Pique int ret;
727*84e872a0SLloyd Pique
728*84e872a0SLloyd Pique while (true) {
729*84e872a0SLloyd Pique /* Dispatching should eventually hit the protocol error before
730*84e872a0SLloyd Pique * any other error. */
731*84e872a0SLloyd Pique ret = wl_display_dispatch(c->wl_display);
732*84e872a0SLloyd Pique if (ret == 0) {
733*84e872a0SLloyd Pique continue;
734*84e872a0SLloyd Pique } else {
735*84e872a0SLloyd Pique assert(errno == EPROTO);
736*84e872a0SLloyd Pique break;
737*84e872a0SLloyd Pique }
738*84e872a0SLloyd Pique }
739*84e872a0SLloyd Pique
740*84e872a0SLloyd Pique check_pending_error(c, proxy);
741*84e872a0SLloyd Pique }
742*84e872a0SLloyd Pique
743*84e872a0SLloyd Pique static void
wait_for_error_using_prepare_read(struct client * c,struct wl_proxy * proxy)744*84e872a0SLloyd Pique wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy)
745*84e872a0SLloyd Pique {
746*84e872a0SLloyd Pique int ret = 0;
747*84e872a0SLloyd Pique struct pollfd pfd[2];
748*84e872a0SLloyd Pique
749*84e872a0SLloyd Pique while (true) {
750*84e872a0SLloyd Pique while (wl_display_prepare_read(c->wl_display) != 0 &&
751*84e872a0SLloyd Pique errno == EAGAIN) {
752*84e872a0SLloyd Pique assert(wl_display_dispatch_pending(c->wl_display) >= 0);
753*84e872a0SLloyd Pique }
754*84e872a0SLloyd Pique
755*84e872a0SLloyd Pique /* Flush may fail due to EPIPE if the connection is broken, but
756*84e872a0SLloyd Pique * this must not set a fatal display error because that would
757*84e872a0SLloyd Pique * result in it being impossible to read a potential protocol
758*84e872a0SLloyd Pique * error. */
759*84e872a0SLloyd Pique do {
760*84e872a0SLloyd Pique ret = wl_display_flush(c->wl_display);
761*84e872a0SLloyd Pique } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
762*84e872a0SLloyd Pique assert(ret >= 0 || errno == EPIPE);
763*84e872a0SLloyd Pique assert(wl_display_get_error(c->wl_display) == 0);
764*84e872a0SLloyd Pique
765*84e872a0SLloyd Pique pfd[0].fd = wl_display_get_fd(c->wl_display);
766*84e872a0SLloyd Pique pfd[0].events = POLLIN;
767*84e872a0SLloyd Pique do {
768*84e872a0SLloyd Pique ret = poll(pfd, 1, -1);
769*84e872a0SLloyd Pique } while (ret == -1 && errno == EINTR);
770*84e872a0SLloyd Pique assert(ret != -1);
771*84e872a0SLloyd Pique
772*84e872a0SLloyd Pique /* We should always manage to read the error before the EPIPE
773*84e872a0SLloyd Pique * comes this way. */
774*84e872a0SLloyd Pique assert(wl_display_read_events(c->wl_display) == 0);
775*84e872a0SLloyd Pique
776*84e872a0SLloyd Pique /* Dispatching should eventually hit the protocol error before
777*84e872a0SLloyd Pique * any other error. */
778*84e872a0SLloyd Pique ret = wl_display_dispatch_pending(c->wl_display);
779*84e872a0SLloyd Pique if (ret == 0) {
780*84e872a0SLloyd Pique continue;
781*84e872a0SLloyd Pique } else {
782*84e872a0SLloyd Pique assert(errno == EPROTO);
783*84e872a0SLloyd Pique break;
784*84e872a0SLloyd Pique }
785*84e872a0SLloyd Pique }
786*84e872a0SLloyd Pique
787*84e872a0SLloyd Pique check_pending_error(c, proxy);
788*84e872a0SLloyd Pique }
789*84e872a0SLloyd Pique
790*84e872a0SLloyd Pique static void
check_error_after_epipe(void * data)791*84e872a0SLloyd Pique check_error_after_epipe(void *data)
792*84e872a0SLloyd Pique {
793*84e872a0SLloyd Pique bool use_dispatch_helpers = *(bool *) data;
794*84e872a0SLloyd Pique struct client *client;
795*84e872a0SLloyd Pique struct wl_seat *seat;
796*84e872a0SLloyd Pique struct wl_callback *callback;
797*84e872a0SLloyd Pique
798*84e872a0SLloyd Pique client = client_connect();
799*84e872a0SLloyd Pique
800*84e872a0SLloyd Pique /* This will, according to the implementation below, cause the server
801*84e872a0SLloyd Pique * to post an error. */
802*84e872a0SLloyd Pique seat = client_get_seat(client);
803*84e872a0SLloyd Pique wl_display_flush(client->wl_display);
804*84e872a0SLloyd Pique
805*84e872a0SLloyd Pique /* The server will not actually destroy the client until it receives
806*84e872a0SLloyd Pique * input, so send something to trigger the client destruction. */
807*84e872a0SLloyd Pique callback = wl_display_sync(client->wl_display);
808*84e872a0SLloyd Pique wl_callback_destroy(callback);
809*84e872a0SLloyd Pique
810*84e872a0SLloyd Pique /* Sleep some to give the server a chance to react and destroy the
811*84e872a0SLloyd Pique * client. */
812*84e872a0SLloyd Pique test_usleep(200000);
813*84e872a0SLloyd Pique
814*84e872a0SLloyd Pique /* Wait for the protocol error and check that we reached it before
815*84e872a0SLloyd Pique * EPIPE. */
816*84e872a0SLloyd Pique if (use_dispatch_helpers) {
817*84e872a0SLloyd Pique wait_for_error_using_dispatch(client, (struct wl_proxy *) seat);
818*84e872a0SLloyd Pique } else {
819*84e872a0SLloyd Pique wait_for_error_using_prepare_read(client,
820*84e872a0SLloyd Pique (struct wl_proxy *) seat);
821*84e872a0SLloyd Pique }
822*84e872a0SLloyd Pique
823*84e872a0SLloyd Pique wl_seat_destroy(seat);
824*84e872a0SLloyd Pique client_disconnect_nocheck(client);
825*84e872a0SLloyd Pique }
826*84e872a0SLloyd Pique
827*84e872a0SLloyd Pique static void
bind_seat_and_post_error(struct wl_client * client,void * data,uint32_t version,uint32_t id)828*84e872a0SLloyd Pique bind_seat_and_post_error(struct wl_client *client, void *data,
829*84e872a0SLloyd Pique uint32_t version, uint32_t id)
830*84e872a0SLloyd Pique {
831*84e872a0SLloyd Pique struct display *d = data;
832*84e872a0SLloyd Pique struct client_info *ci;
833*84e872a0SLloyd Pique struct wl_resource *resource;
834*84e872a0SLloyd Pique
835*84e872a0SLloyd Pique ci = find_client_info(d, client);
836*84e872a0SLloyd Pique assert(ci);
837*84e872a0SLloyd Pique
838*84e872a0SLloyd Pique resource = wl_resource_create(client, &wl_seat_interface, version, id);
839*84e872a0SLloyd Pique assert(resource);
840*84e872a0SLloyd Pique ci->data = resource;
841*84e872a0SLloyd Pique
842*84e872a0SLloyd Pique wl_resource_post_error(ci->data, 23, "Dummy error");
843*84e872a0SLloyd Pique }
844*84e872a0SLloyd Pique
TEST(error_code_after_epipe)845*84e872a0SLloyd Pique TEST(error_code_after_epipe)
846*84e872a0SLloyd Pique {
847*84e872a0SLloyd Pique struct display *d = display_create();
848*84e872a0SLloyd Pique bool use_dispatch_helpers;
849*84e872a0SLloyd Pique
850*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
851*84e872a0SLloyd Pique 1, d, bind_seat_and_post_error);
852*84e872a0SLloyd Pique
853*84e872a0SLloyd Pique use_dispatch_helpers = true;
854*84e872a0SLloyd Pique client_create(d, check_error_after_epipe, &use_dispatch_helpers);
855*84e872a0SLloyd Pique display_run(d);
856*84e872a0SLloyd Pique
857*84e872a0SLloyd Pique use_dispatch_helpers = false;
858*84e872a0SLloyd Pique client_create(d, check_error_after_epipe, &use_dispatch_helpers);
859*84e872a0SLloyd Pique display_run(d);
860*84e872a0SLloyd Pique
861*84e872a0SLloyd Pique display_destroy(d);
862*84e872a0SLloyd Pique }
863*84e872a0SLloyd Pique
864*84e872a0SLloyd Pique static void
check_seat_versions(struct wl_seat * seat,uint32_t ev)865*84e872a0SLloyd Pique check_seat_versions(struct wl_seat *seat, uint32_t ev)
866*84e872a0SLloyd Pique {
867*84e872a0SLloyd Pique struct wl_pointer *pointer;
868*84e872a0SLloyd Pique
869*84e872a0SLloyd Pique assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev);
870*84e872a0SLloyd Pique assert(wl_seat_get_version(seat) == ev);
871*84e872a0SLloyd Pique
872*84e872a0SLloyd Pique pointer = wl_seat_get_pointer(seat);
873*84e872a0SLloyd Pique assert(wl_pointer_get_version(pointer) == ev);
874*84e872a0SLloyd Pique assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev);
875*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) pointer);
876*84e872a0SLloyd Pique }
877*84e872a0SLloyd Pique
878*84e872a0SLloyd Pique /* Normal client with proxy versions available. */
879*84e872a0SLloyd Pique static void
seat_version(void * data)880*84e872a0SLloyd Pique seat_version(void *data)
881*84e872a0SLloyd Pique {
882*84e872a0SLloyd Pique struct handler_info *hi = data;
883*84e872a0SLloyd Pique struct client *c = client_connect();
884*84e872a0SLloyd Pique struct wl_seat *seat;
885*84e872a0SLloyd Pique
886*84e872a0SLloyd Pique /* display proxy should always be version 0 */
887*84e872a0SLloyd Pique assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0);
888*84e872a0SLloyd Pique
889*84e872a0SLloyd Pique seat = client_get_seat_with_info(c, hi);
890*84e872a0SLloyd Pique if (hi->use_unversioned)
891*84e872a0SLloyd Pique check_seat_versions(seat, 0);
892*84e872a0SLloyd Pique else
893*84e872a0SLloyd Pique check_seat_versions(seat, hi->bind_version);
894*84e872a0SLloyd Pique
895*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
896*84e872a0SLloyd Pique
897*84e872a0SLloyd Pique client_disconnect_nocheck(c);
898*84e872a0SLloyd Pique }
899*84e872a0SLloyd Pique
TEST(versions)900*84e872a0SLloyd Pique TEST(versions)
901*84e872a0SLloyd Pique {
902*84e872a0SLloyd Pique struct display *d = display_create();
903*84e872a0SLloyd Pique struct wl_global *global;
904*84e872a0SLloyd Pique int i;
905*84e872a0SLloyd Pique
906*84e872a0SLloyd Pique global = wl_global_create(d->wl_display, &wl_seat_interface,
907*84e872a0SLloyd Pique 5, d, bind_seat);
908*84e872a0SLloyd Pique
909*84e872a0SLloyd Pique for (i = 1; i <= 5; i++) {
910*84e872a0SLloyd Pique struct handler_info hi;
911*84e872a0SLloyd Pique
912*84e872a0SLloyd Pique hi.bind_version = i;
913*84e872a0SLloyd Pique hi.use_unversioned = false;
914*84e872a0SLloyd Pique client_create(d, seat_version, &hi);
915*84e872a0SLloyd Pique hi.use_unversioned = true;
916*84e872a0SLloyd Pique client_create(d, seat_version, &hi);
917*84e872a0SLloyd Pique }
918*84e872a0SLloyd Pique
919*84e872a0SLloyd Pique display_run(d);
920*84e872a0SLloyd Pique
921*84e872a0SLloyd Pique wl_global_destroy(global);
922*84e872a0SLloyd Pique
923*84e872a0SLloyd Pique display_destroy(d);
924*84e872a0SLloyd Pique }
925*84e872a0SLloyd Pique
926*84e872a0SLloyd Pique static void
check_error_on_destroyed_object(void * data)927*84e872a0SLloyd Pique check_error_on_destroyed_object(void *data)
928*84e872a0SLloyd Pique {
929*84e872a0SLloyd Pique struct client *c;
930*84e872a0SLloyd Pique struct wl_seat *seat;
931*84e872a0SLloyd Pique uint32_t id;
932*84e872a0SLloyd Pique const struct wl_interface *intf;
933*84e872a0SLloyd Pique
934*84e872a0SLloyd Pique c = client_connect();
935*84e872a0SLloyd Pique seat = client_get_seat(c);
936*84e872a0SLloyd Pique
937*84e872a0SLloyd Pique /* destroy the seat proxy. The display won't know
938*84e872a0SLloyd Pique * about it yet, so it will post the error as usual */
939*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) seat);
940*84e872a0SLloyd Pique
941*84e872a0SLloyd Pique /* let display post the error. The error will
942*84e872a0SLloyd Pique * be caught in stop_display while dispatching */
943*84e872a0SLloyd Pique assert(stop_display(c, 1) == -1);
944*84e872a0SLloyd Pique
945*84e872a0SLloyd Pique /* check the returned error. Since the object was destroyed,
946*84e872a0SLloyd Pique * we don't know the interface and id */
947*84e872a0SLloyd Pique assert(wl_display_get_error(c->wl_display) == EPROTO);
948*84e872a0SLloyd Pique assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23);
949*84e872a0SLloyd Pique assert(intf == NULL);
950*84e872a0SLloyd Pique assert(id == 0);
951*84e872a0SLloyd Pique
952*84e872a0SLloyd Pique client_disconnect_nocheck(c);
953*84e872a0SLloyd Pique }
954*84e872a0SLloyd Pique
TEST(error_on_destroyed_object)955*84e872a0SLloyd Pique TEST(error_on_destroyed_object)
956*84e872a0SLloyd Pique {
957*84e872a0SLloyd Pique struct client_info *cl;
958*84e872a0SLloyd Pique struct display *d = display_create();
959*84e872a0SLloyd Pique
960*84e872a0SLloyd Pique wl_global_create(d->wl_display, &wl_seat_interface,
961*84e872a0SLloyd Pique 1, d, bind_seat);
962*84e872a0SLloyd Pique
963*84e872a0SLloyd Pique cl = client_create_noarg(d, check_error_on_destroyed_object);
964*84e872a0SLloyd Pique display_run(d);
965*84e872a0SLloyd Pique
966*84e872a0SLloyd Pique /* did client bind to the seat? */
967*84e872a0SLloyd Pique assert(cl->data);
968*84e872a0SLloyd Pique
969*84e872a0SLloyd Pique /* post error on the destroyed object */
970*84e872a0SLloyd Pique wl_resource_post_error((struct wl_resource *) cl->data,
971*84e872a0SLloyd Pique 23, "Dummy error");
972*84e872a0SLloyd Pique display_resume(d);
973*84e872a0SLloyd Pique display_destroy(d);
974*84e872a0SLloyd Pique }
975*84e872a0SLloyd Pique
976*84e872a0SLloyd Pique static bool
global_filter(const struct wl_client * client,const struct wl_global * global,void * data)977*84e872a0SLloyd Pique global_filter(const struct wl_client *client,
978*84e872a0SLloyd Pique const struct wl_global *global,
979*84e872a0SLloyd Pique void *data)
980*84e872a0SLloyd Pique {
981*84e872a0SLloyd Pique /* Hide the wl_data_offer interface if no data was provided */
982*84e872a0SLloyd Pique if (wl_global_get_interface(global) == &wl_data_offer_interface)
983*84e872a0SLloyd Pique return data != NULL;
984*84e872a0SLloyd Pique
985*84e872a0SLloyd Pique /* Show all the others */
986*84e872a0SLloyd Pique return true;
987*84e872a0SLloyd Pique }
988*84e872a0SLloyd Pique
989*84e872a0SLloyd Pique static void
bind_data_offer(struct wl_client * client,void * data,uint32_t vers,uint32_t id)990*84e872a0SLloyd Pique bind_data_offer(struct wl_client *client, void *data,
991*84e872a0SLloyd Pique uint32_t vers, uint32_t id)
992*84e872a0SLloyd Pique {
993*84e872a0SLloyd Pique /* Client should not be able to bind to this interface! */
994*84e872a0SLloyd Pique assert(false);
995*84e872a0SLloyd Pique }
996*84e872a0SLloyd Pique
997*84e872a0SLloyd Pique static void
registry_handle_filtered(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)998*84e872a0SLloyd Pique registry_handle_filtered(void *data, struct wl_registry *registry,
999*84e872a0SLloyd Pique uint32_t id, const char *intf, uint32_t ver)
1000*84e872a0SLloyd Pique {
1001*84e872a0SLloyd Pique uint32_t *name = data;
1002*84e872a0SLloyd Pique
1003*84e872a0SLloyd Pique if (strcmp (intf, "wl_data_offer") == 0) {
1004*84e872a0SLloyd Pique assert(name);
1005*84e872a0SLloyd Pique *name = id;
1006*84e872a0SLloyd Pique }
1007*84e872a0SLloyd Pique }
1008*84e872a0SLloyd Pique
1009*84e872a0SLloyd Pique static void
registry_handle_remove_filtered(void * data,struct wl_registry * registry,uint32_t id)1010*84e872a0SLloyd Pique registry_handle_remove_filtered(void *data, struct wl_registry *registry,
1011*84e872a0SLloyd Pique uint32_t id)
1012*84e872a0SLloyd Pique {
1013*84e872a0SLloyd Pique assert(false);
1014*84e872a0SLloyd Pique }
1015*84e872a0SLloyd Pique
1016*84e872a0SLloyd Pique static const struct wl_registry_listener registry_listener_filtered = {
1017*84e872a0SLloyd Pique registry_handle_filtered,
1018*84e872a0SLloyd Pique registry_handle_remove_filtered,
1019*84e872a0SLloyd Pique };
1020*84e872a0SLloyd Pique
1021*84e872a0SLloyd Pique static void
get_globals(void * data)1022*84e872a0SLloyd Pique get_globals(void *data)
1023*84e872a0SLloyd Pique {
1024*84e872a0SLloyd Pique struct client *c = client_connect();
1025*84e872a0SLloyd Pique struct wl_registry *registry;
1026*84e872a0SLloyd Pique
1027*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1028*84e872a0SLloyd Pique wl_registry_add_listener(registry, ®istry_listener_filtered, data);
1029*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1030*84e872a0SLloyd Pique
1031*84e872a0SLloyd Pique wl_registry_destroy(registry);
1032*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1033*84e872a0SLloyd Pique }
1034*84e872a0SLloyd Pique
TEST(filtered_global_is_hidden)1035*84e872a0SLloyd Pique TEST(filtered_global_is_hidden)
1036*84e872a0SLloyd Pique {
1037*84e872a0SLloyd Pique struct display *d;
1038*84e872a0SLloyd Pique struct wl_global *g;
1039*84e872a0SLloyd Pique
1040*84e872a0SLloyd Pique d = display_create();
1041*84e872a0SLloyd Pique
1042*84e872a0SLloyd Pique g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1043*84e872a0SLloyd Pique 1, d, bind_data_offer);
1044*84e872a0SLloyd Pique wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1045*84e872a0SLloyd Pique
1046*84e872a0SLloyd Pique client_create_noarg(d, get_globals);
1047*84e872a0SLloyd Pique display_run(d);
1048*84e872a0SLloyd Pique
1049*84e872a0SLloyd Pique wl_global_destroy(g);
1050*84e872a0SLloyd Pique
1051*84e872a0SLloyd Pique display_destroy(d);
1052*84e872a0SLloyd Pique }
1053*84e872a0SLloyd Pique
1054*84e872a0SLloyd Pique static void
get_dynamic_globals(void * data)1055*84e872a0SLloyd Pique get_dynamic_globals(void *data)
1056*84e872a0SLloyd Pique {
1057*84e872a0SLloyd Pique struct client *c = client_connect();
1058*84e872a0SLloyd Pique struct wl_registry *registry;
1059*84e872a0SLloyd Pique
1060*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1061*84e872a0SLloyd Pique wl_registry_add_listener(registry, ®istry_listener_filtered, data);
1062*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1063*84e872a0SLloyd Pique
1064*84e872a0SLloyd Pique /* Wait for the server to create a new global */
1065*84e872a0SLloyd Pique assert(stop_display(c, 1) >= 0);
1066*84e872a0SLloyd Pique
1067*84e872a0SLloyd Pique /* Check that we don't see it */
1068*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1069*84e872a0SLloyd Pique
1070*84e872a0SLloyd Pique /* Wait for the server to remove that global */
1071*84e872a0SLloyd Pique assert(stop_display(c, 1) >= 0);
1072*84e872a0SLloyd Pique
1073*84e872a0SLloyd Pique /* Check that we don't get a global_remove event */
1074*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1075*84e872a0SLloyd Pique
1076*84e872a0SLloyd Pique wl_registry_destroy(registry);
1077*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1078*84e872a0SLloyd Pique }
1079*84e872a0SLloyd Pique
TEST(filtered_dynamic_global_is_hidden)1080*84e872a0SLloyd Pique TEST(filtered_dynamic_global_is_hidden)
1081*84e872a0SLloyd Pique {
1082*84e872a0SLloyd Pique struct display *d;
1083*84e872a0SLloyd Pique struct wl_global *g;
1084*84e872a0SLloyd Pique
1085*84e872a0SLloyd Pique d = display_create();
1086*84e872a0SLloyd Pique wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1087*84e872a0SLloyd Pique
1088*84e872a0SLloyd Pique /* Create a client and let it enumerate the globals */
1089*84e872a0SLloyd Pique client_create_noarg(d, get_dynamic_globals);
1090*84e872a0SLloyd Pique display_run(d);
1091*84e872a0SLloyd Pique
1092*84e872a0SLloyd Pique /* Dynamically create a new global */
1093*84e872a0SLloyd Pique g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1094*84e872a0SLloyd Pique 1, d, bind_data_offer);
1095*84e872a0SLloyd Pique
1096*84e872a0SLloyd Pique display_resume(d);
1097*84e872a0SLloyd Pique
1098*84e872a0SLloyd Pique /* Dynamically remove the global */
1099*84e872a0SLloyd Pique wl_global_destroy(g);
1100*84e872a0SLloyd Pique
1101*84e872a0SLloyd Pique display_resume(d);
1102*84e872a0SLloyd Pique
1103*84e872a0SLloyd Pique display_destroy(d);
1104*84e872a0SLloyd Pique }
1105*84e872a0SLloyd Pique
1106*84e872a0SLloyd Pique static void
check_bind_error(struct client * c)1107*84e872a0SLloyd Pique check_bind_error(struct client *c)
1108*84e872a0SLloyd Pique {
1109*84e872a0SLloyd Pique uint32_t errorcode, id;
1110*84e872a0SLloyd Pique int err;
1111*84e872a0SLloyd Pique const struct wl_interface *intf;
1112*84e872a0SLloyd Pique
1113*84e872a0SLloyd Pique err = wl_display_get_error(c->wl_display);
1114*84e872a0SLloyd Pique assert(err == EPROTO);
1115*84e872a0SLloyd Pique
1116*84e872a0SLloyd Pique errorcode = wl_display_get_protocol_error(c->wl_display, &intf, &id);
1117*84e872a0SLloyd Pique assert(errorcode == WL_DISPLAY_ERROR_INVALID_OBJECT);
1118*84e872a0SLloyd Pique }
1119*84e872a0SLloyd Pique
1120*84e872a0SLloyd Pique static void
force_bind(void * data)1121*84e872a0SLloyd Pique force_bind(void *data)
1122*84e872a0SLloyd Pique {
1123*84e872a0SLloyd Pique struct client *c = client_connect();
1124*84e872a0SLloyd Pique struct wl_registry *registry;
1125*84e872a0SLloyd Pique void *ptr;
1126*84e872a0SLloyd Pique uint32_t *name = data;
1127*84e872a0SLloyd Pique
1128*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1129*84e872a0SLloyd Pique
1130*84e872a0SLloyd Pique ptr = wl_registry_bind (registry, *name, &wl_data_offer_interface, 1);
1131*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1132*84e872a0SLloyd Pique check_bind_error(c);
1133*84e872a0SLloyd Pique
1134*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) ptr);
1135*84e872a0SLloyd Pique wl_registry_destroy(registry);
1136*84e872a0SLloyd Pique
1137*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1138*84e872a0SLloyd Pique }
1139*84e872a0SLloyd Pique
TEST(bind_fails_on_filtered_global)1140*84e872a0SLloyd Pique TEST(bind_fails_on_filtered_global)
1141*84e872a0SLloyd Pique {
1142*84e872a0SLloyd Pique struct display *d;
1143*84e872a0SLloyd Pique struct wl_global *g;
1144*84e872a0SLloyd Pique uint32_t *name;
1145*84e872a0SLloyd Pique
1146*84e872a0SLloyd Pique /* Create a anonymous shared memory to pass the interface name */
1147*84e872a0SLloyd Pique name = mmap(NULL, sizeof(uint32_t),
1148*84e872a0SLloyd Pique PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
1149*84e872a0SLloyd Pique
1150*84e872a0SLloyd Pique d = display_create();
1151*84e872a0SLloyd Pique
1152*84e872a0SLloyd Pique g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1153*84e872a0SLloyd Pique 1, d, bind_data_offer);
1154*84e872a0SLloyd Pique wl_display_set_global_filter(d->wl_display, global_filter, name);
1155*84e872a0SLloyd Pique
1156*84e872a0SLloyd Pique client_create(d, get_globals, name);
1157*84e872a0SLloyd Pique *name = 0;
1158*84e872a0SLloyd Pique
1159*84e872a0SLloyd Pique display_run(d);
1160*84e872a0SLloyd Pique /* wl_data_offer should be 2 */
1161*84e872a0SLloyd Pique assert(*name == 2);
1162*84e872a0SLloyd Pique wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1163*84e872a0SLloyd Pique
1164*84e872a0SLloyd Pique /* Try to bind to the interface name when a global filter is in place */
1165*84e872a0SLloyd Pique client_create(d, force_bind, name);
1166*84e872a0SLloyd Pique display_run(d);
1167*84e872a0SLloyd Pique
1168*84e872a0SLloyd Pique wl_global_destroy(g);
1169*84e872a0SLloyd Pique
1170*84e872a0SLloyd Pique display_destroy(d);
1171*84e872a0SLloyd Pique }
1172*84e872a0SLloyd Pique
1173*84e872a0SLloyd Pique static void
pre_fd(void * data,struct fd_passer * fdp)1174*84e872a0SLloyd Pique pre_fd(void *data, struct fd_passer *fdp)
1175*84e872a0SLloyd Pique {
1176*84e872a0SLloyd Pique fd_passer_destroy(fdp);
1177*84e872a0SLloyd Pique }
1178*84e872a0SLloyd Pique
1179*84e872a0SLloyd Pique static void
fd(void * data,struct fd_passer * fdp,int32_t fd)1180*84e872a0SLloyd Pique fd(void *data, struct fd_passer *fdp, int32_t fd)
1181*84e872a0SLloyd Pique {
1182*84e872a0SLloyd Pique /* We destroyed the resource before this event */
1183*84e872a0SLloyd Pique assert(false);
1184*84e872a0SLloyd Pique }
1185*84e872a0SLloyd Pique
1186*84e872a0SLloyd Pique struct fd_passer_listener fd_passer_listener = {
1187*84e872a0SLloyd Pique pre_fd,
1188*84e872a0SLloyd Pique fd,
1189*84e872a0SLloyd Pique };
1190*84e872a0SLloyd Pique
1191*84e872a0SLloyd Pique static void
zombie_fd_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1192*84e872a0SLloyd Pique zombie_fd_handle_globals(void *data, struct wl_registry *registry,
1193*84e872a0SLloyd Pique uint32_t id, const char *intf, uint32_t ver)
1194*84e872a0SLloyd Pique {
1195*84e872a0SLloyd Pique struct fd_passer *fdp;
1196*84e872a0SLloyd Pique
1197*84e872a0SLloyd Pique if (!strcmp(intf, "fd_passer")) {
1198*84e872a0SLloyd Pique fdp = wl_registry_bind(registry, id, &fd_passer_interface, 1);
1199*84e872a0SLloyd Pique fd_passer_add_listener(fdp, &fd_passer_listener, NULL);
1200*84e872a0SLloyd Pique }
1201*84e872a0SLloyd Pique }
1202*84e872a0SLloyd Pique
1203*84e872a0SLloyd Pique static const struct wl_registry_listener zombie_fd_registry_listener = {
1204*84e872a0SLloyd Pique zombie_fd_handle_globals,
1205*84e872a0SLloyd Pique NULL
1206*84e872a0SLloyd Pique };
1207*84e872a0SLloyd Pique
1208*84e872a0SLloyd Pique static void
zombie_client(void * data)1209*84e872a0SLloyd Pique zombie_client(void *data)
1210*84e872a0SLloyd Pique {
1211*84e872a0SLloyd Pique struct client *c = client_connect();
1212*84e872a0SLloyd Pique struct wl_registry *registry;
1213*84e872a0SLloyd Pique
1214*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1215*84e872a0SLloyd Pique wl_registry_add_listener(registry, &zombie_fd_registry_listener, NULL);
1216*84e872a0SLloyd Pique
1217*84e872a0SLloyd Pique /* Gets the registry */
1218*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1219*84e872a0SLloyd Pique
1220*84e872a0SLloyd Pique /* push out the fd_passer bind */
1221*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1222*84e872a0SLloyd Pique
1223*84e872a0SLloyd Pique /* push out our fd_passer.destroy */
1224*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1225*84e872a0SLloyd Pique
1226*84e872a0SLloyd Pique wl_registry_destroy(registry);
1227*84e872a0SLloyd Pique
1228*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1229*84e872a0SLloyd Pique }
1230*84e872a0SLloyd Pique
1231*84e872a0SLloyd Pique struct passer_data {
1232*84e872a0SLloyd Pique struct wl_resource *conjoined_passer;
1233*84e872a0SLloyd Pique };
1234*84e872a0SLloyd Pique
1235*84e872a0SLloyd Pique static void
feed_pipe(int fd,char tosend)1236*84e872a0SLloyd Pique feed_pipe(int fd, char tosend)
1237*84e872a0SLloyd Pique {
1238*84e872a0SLloyd Pique int count;
1239*84e872a0SLloyd Pique
1240*84e872a0SLloyd Pique do {
1241*84e872a0SLloyd Pique count = write(fd, &tosend, 1);
1242*84e872a0SLloyd Pique } while (count != 1 && errno == EAGAIN);
1243*84e872a0SLloyd Pique assert(count == 1);
1244*84e872a0SLloyd Pique close(fd);
1245*84e872a0SLloyd Pique }
1246*84e872a0SLloyd Pique
1247*84e872a0SLloyd Pique static void
fd_passer_clobber(struct wl_client * client,struct wl_resource * res)1248*84e872a0SLloyd Pique fd_passer_clobber(struct wl_client *client, struct wl_resource *res)
1249*84e872a0SLloyd Pique {
1250*84e872a0SLloyd Pique struct passer_data *pdata = wl_resource_get_user_data(res);
1251*84e872a0SLloyd Pique int pipes1[2], pipes2[2], ret;
1252*84e872a0SLloyd Pique
1253*84e872a0SLloyd Pique if (pdata->conjoined_passer) {
1254*84e872a0SLloyd Pique ret = pipe(pipes1);
1255*84e872a0SLloyd Pique assert(ret == 0);
1256*84e872a0SLloyd Pique ret = pipe(pipes2);
1257*84e872a0SLloyd Pique assert(ret == 0);
1258*84e872a0SLloyd Pique
1259*84e872a0SLloyd Pique wl_resource_queue_event(res, FD_PASSER_FD, pipes1[0]);
1260*84e872a0SLloyd Pique fd_passer_send_fd(pdata->conjoined_passer, pipes2[0]);
1261*84e872a0SLloyd Pique feed_pipe(pipes1[1], '1');
1262*84e872a0SLloyd Pique feed_pipe(pipes2[1], '2');
1263*84e872a0SLloyd Pique close(pipes1[0]);
1264*84e872a0SLloyd Pique close(pipes2[0]);
1265*84e872a0SLloyd Pique }
1266*84e872a0SLloyd Pique wl_resource_destroy(res);
1267*84e872a0SLloyd Pique }
1268*84e872a0SLloyd Pique
1269*84e872a0SLloyd Pique static void
fd_passer_twin(struct wl_client * client,struct wl_resource * res,struct wl_resource * passer)1270*84e872a0SLloyd Pique fd_passer_twin(struct wl_client *client, struct wl_resource *res, struct wl_resource *passer)
1271*84e872a0SLloyd Pique {
1272*84e872a0SLloyd Pique struct passer_data *pdata = wl_resource_get_user_data(res);
1273*84e872a0SLloyd Pique
1274*84e872a0SLloyd Pique pdata->conjoined_passer = passer;
1275*84e872a0SLloyd Pique }
1276*84e872a0SLloyd Pique
1277*84e872a0SLloyd Pique static const struct fd_passer_interface fdp_interface = {
1278*84e872a0SLloyd Pique fd_passer_clobber,
1279*84e872a0SLloyd Pique fd_passer_twin
1280*84e872a0SLloyd Pique };
1281*84e872a0SLloyd Pique
1282*84e872a0SLloyd Pique static void
pdata_destroy(struct wl_resource * res)1283*84e872a0SLloyd Pique pdata_destroy(struct wl_resource *res)
1284*84e872a0SLloyd Pique {
1285*84e872a0SLloyd Pique struct passer_data *pdata = wl_resource_get_user_data(res);
1286*84e872a0SLloyd Pique
1287*84e872a0SLloyd Pique free(pdata);
1288*84e872a0SLloyd Pique }
1289*84e872a0SLloyd Pique
1290*84e872a0SLloyd Pique static void
bind_fd_passer(struct wl_client * client,void * data,uint32_t vers,uint32_t id)1291*84e872a0SLloyd Pique bind_fd_passer(struct wl_client *client, void *data,
1292*84e872a0SLloyd Pique uint32_t vers, uint32_t id)
1293*84e872a0SLloyd Pique {
1294*84e872a0SLloyd Pique struct wl_resource *res;
1295*84e872a0SLloyd Pique struct passer_data *pdata;
1296*84e872a0SLloyd Pique
1297*84e872a0SLloyd Pique pdata = malloc(sizeof(*pdata));
1298*84e872a0SLloyd Pique assert(pdata);
1299*84e872a0SLloyd Pique pdata->conjoined_passer = NULL;
1300*84e872a0SLloyd Pique
1301*84e872a0SLloyd Pique res = wl_resource_create(client, &fd_passer_interface, vers, id);
1302*84e872a0SLloyd Pique wl_resource_set_implementation(res, &fdp_interface, pdata, pdata_destroy);
1303*84e872a0SLloyd Pique assert(res);
1304*84e872a0SLloyd Pique if (vers == 1) {
1305*84e872a0SLloyd Pique fd_passer_send_pre_fd(res);
1306*84e872a0SLloyd Pique fd_passer_send_fd(res, fileno(stdin));
1307*84e872a0SLloyd Pique }
1308*84e872a0SLloyd Pique }
1309*84e872a0SLloyd Pique
TEST(zombie_fd)1310*84e872a0SLloyd Pique TEST(zombie_fd)
1311*84e872a0SLloyd Pique {
1312*84e872a0SLloyd Pique struct display *d;
1313*84e872a0SLloyd Pique struct wl_global *g;
1314*84e872a0SLloyd Pique
1315*84e872a0SLloyd Pique d = display_create();
1316*84e872a0SLloyd Pique
1317*84e872a0SLloyd Pique g = wl_global_create(d->wl_display, &fd_passer_interface,
1318*84e872a0SLloyd Pique 1, d, bind_fd_passer);
1319*84e872a0SLloyd Pique
1320*84e872a0SLloyd Pique client_create_noarg(d, zombie_client);
1321*84e872a0SLloyd Pique display_run(d);
1322*84e872a0SLloyd Pique
1323*84e872a0SLloyd Pique wl_global_destroy(g);
1324*84e872a0SLloyd Pique
1325*84e872a0SLloyd Pique display_destroy(d);
1326*84e872a0SLloyd Pique }
1327*84e872a0SLloyd Pique
1328*84e872a0SLloyd Pique
1329*84e872a0SLloyd Pique static void
double_pre_fd(void * data,struct fd_passer * fdp)1330*84e872a0SLloyd Pique double_pre_fd(void *data, struct fd_passer *fdp)
1331*84e872a0SLloyd Pique {
1332*84e872a0SLloyd Pique assert(false);
1333*84e872a0SLloyd Pique }
1334*84e872a0SLloyd Pique
1335*84e872a0SLloyd Pique static void
double_fd(void * data,struct fd_passer * fdp,int32_t fd)1336*84e872a0SLloyd Pique double_fd(void *data, struct fd_passer *fdp, int32_t fd)
1337*84e872a0SLloyd Pique {
1338*84e872a0SLloyd Pique char buf;
1339*84e872a0SLloyd Pique int count;
1340*84e872a0SLloyd Pique
1341*84e872a0SLloyd Pique do {
1342*84e872a0SLloyd Pique count = read(fd, &buf, 1);
1343*84e872a0SLloyd Pique } while (count != 1 && errno == EAGAIN);
1344*84e872a0SLloyd Pique assert(count == 1);
1345*84e872a0SLloyd Pique
1346*84e872a0SLloyd Pique close(fd);
1347*84e872a0SLloyd Pique fd_passer_destroy(fdp);
1348*84e872a0SLloyd Pique assert(buf == '2');
1349*84e872a0SLloyd Pique }
1350*84e872a0SLloyd Pique
1351*84e872a0SLloyd Pique struct fd_passer_listener double_fd_passer_listener = {
1352*84e872a0SLloyd Pique double_pre_fd,
1353*84e872a0SLloyd Pique double_fd,
1354*84e872a0SLloyd Pique };
1355*84e872a0SLloyd Pique
1356*84e872a0SLloyd Pique
1357*84e872a0SLloyd Pique static void
double_zombie_fd_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1358*84e872a0SLloyd Pique double_zombie_fd_handle_globals(void *data, struct wl_registry *registry,
1359*84e872a0SLloyd Pique uint32_t id, const char *intf, uint32_t ver)
1360*84e872a0SLloyd Pique {
1361*84e872a0SLloyd Pique struct fd_passer *fdp1, *fdp2;
1362*84e872a0SLloyd Pique
1363*84e872a0SLloyd Pique if (!strcmp(intf, "fd_passer")) {
1364*84e872a0SLloyd Pique fdp1 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
1365*84e872a0SLloyd Pique fd_passer_add_listener(fdp1, &double_fd_passer_listener, NULL);
1366*84e872a0SLloyd Pique fdp2 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
1367*84e872a0SLloyd Pique fd_passer_add_listener(fdp2, &double_fd_passer_listener, NULL);
1368*84e872a0SLloyd Pique fd_passer_conjoin(fdp1, fdp2);
1369*84e872a0SLloyd Pique fd_passer_destroy(fdp1);
1370*84e872a0SLloyd Pique }
1371*84e872a0SLloyd Pique }
1372*84e872a0SLloyd Pique
1373*84e872a0SLloyd Pique static const struct wl_registry_listener double_zombie_fd_registry_listener = {
1374*84e872a0SLloyd Pique double_zombie_fd_handle_globals,
1375*84e872a0SLloyd Pique NULL
1376*84e872a0SLloyd Pique };
1377*84e872a0SLloyd Pique
1378*84e872a0SLloyd Pique static void
double_zombie_client(void * data)1379*84e872a0SLloyd Pique double_zombie_client(void *data)
1380*84e872a0SLloyd Pique {
1381*84e872a0SLloyd Pique struct client *c = client_connect();
1382*84e872a0SLloyd Pique struct wl_registry *registry;
1383*84e872a0SLloyd Pique
1384*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1385*84e872a0SLloyd Pique wl_registry_add_listener(registry, &double_zombie_fd_registry_listener, NULL);
1386*84e872a0SLloyd Pique
1387*84e872a0SLloyd Pique /* Gets the registry */
1388*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1389*84e872a0SLloyd Pique
1390*84e872a0SLloyd Pique /* One more so server can respond to conjoin+destroy */
1391*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1392*84e872a0SLloyd Pique
1393*84e872a0SLloyd Pique /* And finally push out our last fd_passer.destroy */
1394*84e872a0SLloyd Pique wl_display_roundtrip(c->wl_display);
1395*84e872a0SLloyd Pique
1396*84e872a0SLloyd Pique wl_registry_destroy(registry);
1397*84e872a0SLloyd Pique
1398*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1399*84e872a0SLloyd Pique }
1400*84e872a0SLloyd Pique
TEST(zombie_fd_errant_consumption)1401*84e872a0SLloyd Pique TEST(zombie_fd_errant_consumption)
1402*84e872a0SLloyd Pique {
1403*84e872a0SLloyd Pique struct display *d;
1404*84e872a0SLloyd Pique struct wl_global *g;
1405*84e872a0SLloyd Pique
1406*84e872a0SLloyd Pique d = display_create();
1407*84e872a0SLloyd Pique
1408*84e872a0SLloyd Pique g = wl_global_create(d->wl_display, &fd_passer_interface,
1409*84e872a0SLloyd Pique 2, d, bind_fd_passer);
1410*84e872a0SLloyd Pique
1411*84e872a0SLloyd Pique client_create_noarg(d, double_zombie_client);
1412*84e872a0SLloyd Pique display_run(d);
1413*84e872a0SLloyd Pique
1414*84e872a0SLloyd Pique wl_global_destroy(g);
1415*84e872a0SLloyd Pique
1416*84e872a0SLloyd Pique display_destroy(d);
1417*84e872a0SLloyd Pique }
1418*84e872a0SLloyd Pique
1419*84e872a0SLloyd Pique
1420*84e872a0SLloyd Pique static void
registry_bind_interface_mismatch_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1421*84e872a0SLloyd Pique registry_bind_interface_mismatch_handle_global(void *data,
1422*84e872a0SLloyd Pique struct wl_registry *registry,
1423*84e872a0SLloyd Pique uint32_t id, const char *intf,
1424*84e872a0SLloyd Pique uint32_t ver)
1425*84e872a0SLloyd Pique {
1426*84e872a0SLloyd Pique uint32_t *seat_id_ptr = data;
1427*84e872a0SLloyd Pique
1428*84e872a0SLloyd Pique if (strcmp(intf, wl_seat_interface.name) == 0) {
1429*84e872a0SLloyd Pique *seat_id_ptr = id;
1430*84e872a0SLloyd Pique }
1431*84e872a0SLloyd Pique }
1432*84e872a0SLloyd Pique
1433*84e872a0SLloyd Pique static const struct wl_registry_listener bind_interface_mismatch_registry_listener = {
1434*84e872a0SLloyd Pique registry_bind_interface_mismatch_handle_global,
1435*84e872a0SLloyd Pique NULL
1436*84e872a0SLloyd Pique };
1437*84e872a0SLloyd Pique
1438*84e872a0SLloyd Pique static void
registry_bind_interface_mismatch_client(void * data)1439*84e872a0SLloyd Pique registry_bind_interface_mismatch_client(void *data)
1440*84e872a0SLloyd Pique {
1441*84e872a0SLloyd Pique struct client *c = client_connect();
1442*84e872a0SLloyd Pique struct wl_registry *registry;
1443*84e872a0SLloyd Pique uint32_t seat_id = 0;
1444*84e872a0SLloyd Pique void *ptr;
1445*84e872a0SLloyd Pique int ret;
1446*84e872a0SLloyd Pique
1447*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1448*84e872a0SLloyd Pique wl_registry_add_listener(registry,
1449*84e872a0SLloyd Pique &bind_interface_mismatch_registry_listener,
1450*84e872a0SLloyd Pique &seat_id);
1451*84e872a0SLloyd Pique
1452*84e872a0SLloyd Pique ret = wl_display_roundtrip(c->wl_display);
1453*84e872a0SLloyd Pique assert(ret >= 0);
1454*84e872a0SLloyd Pique assert(seat_id != 0);
1455*84e872a0SLloyd Pique
1456*84e872a0SLloyd Pique /* Bind with a different interface */
1457*84e872a0SLloyd Pique ptr = wl_registry_bind(registry, seat_id, &wl_output_interface, 1);
1458*84e872a0SLloyd Pique ret = wl_display_roundtrip(c->wl_display);
1459*84e872a0SLloyd Pique assert(ret < 0);
1460*84e872a0SLloyd Pique check_bind_error(c);
1461*84e872a0SLloyd Pique
1462*84e872a0SLloyd Pique wl_proxy_destroy((struct wl_proxy *) ptr);
1463*84e872a0SLloyd Pique wl_registry_destroy(registry);
1464*84e872a0SLloyd Pique
1465*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1466*84e872a0SLloyd Pique }
1467*84e872a0SLloyd Pique
TEST(registry_bind_interface_mismatch)1468*84e872a0SLloyd Pique TEST(registry_bind_interface_mismatch)
1469*84e872a0SLloyd Pique {
1470*84e872a0SLloyd Pique struct display *d;
1471*84e872a0SLloyd Pique struct wl_global *seat_global;
1472*84e872a0SLloyd Pique
1473*84e872a0SLloyd Pique d = display_create();
1474*84e872a0SLloyd Pique
1475*84e872a0SLloyd Pique seat_global = wl_global_create(d->wl_display, &wl_seat_interface,
1476*84e872a0SLloyd Pique 1, NULL, NULL);
1477*84e872a0SLloyd Pique
1478*84e872a0SLloyd Pique client_create_noarg(d, registry_bind_interface_mismatch_client);
1479*84e872a0SLloyd Pique display_run(d);
1480*84e872a0SLloyd Pique
1481*84e872a0SLloyd Pique wl_global_destroy(seat_global);
1482*84e872a0SLloyd Pique
1483*84e872a0SLloyd Pique display_destroy(d);
1484*84e872a0SLloyd Pique }
1485*84e872a0SLloyd Pique
1486*84e872a0SLloyd Pique static void
send_overflow_client(void * data)1487*84e872a0SLloyd Pique send_overflow_client(void *data)
1488*84e872a0SLloyd Pique {
1489*84e872a0SLloyd Pique struct client *c = client_connect();
1490*84e872a0SLloyd Pique int i, err = 0;
1491*84e872a0SLloyd Pique int *pipes = data;
1492*84e872a0SLloyd Pique char tmp = '\0';
1493*84e872a0SLloyd Pique int sock, optval = 16384;
1494*84e872a0SLloyd Pique
1495*84e872a0SLloyd Pique /* Limit the send buffer size for the display socket to guarantee
1496*84e872a0SLloyd Pique * that the test will cause an overflow. */
1497*84e872a0SLloyd Pique sock = wl_display_get_fd(c->wl_display);
1498*84e872a0SLloyd Pique assert(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == 0);
1499*84e872a0SLloyd Pique
1500*84e872a0SLloyd Pique /* Request to break out of 'display_run' in the main process */
1501*84e872a0SLloyd Pique assert(stop_display(c, 1) >= 0);
1502*84e872a0SLloyd Pique
1503*84e872a0SLloyd Pique /* On Linux, the actual socket data + metadata space is twice `optval`;
1504*84e872a0SLloyd Pique * since each noop request requires 8 bytes, the buffer should overflow
1505*84e872a0SLloyd Pique * within <=4096 iterations. */
1506*84e872a0SLloyd Pique for (i = 0; i < 1000000; i++) {
1507*84e872a0SLloyd Pique noop_request(c);
1508*84e872a0SLloyd Pique err = wl_display_get_error(c->wl_display);
1509*84e872a0SLloyd Pique if (err)
1510*84e872a0SLloyd Pique break;
1511*84e872a0SLloyd Pique }
1512*84e872a0SLloyd Pique
1513*84e872a0SLloyd Pique /* Do not close the pipe file descriptors afterwards, because the leak
1514*84e872a0SLloyd Pique * check verifies that the initial/final FD counts are the same */
1515*84e872a0SLloyd Pique assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp));
1516*84e872a0SLloyd Pique
1517*84e872a0SLloyd Pique /* Expect an error */
1518*84e872a0SLloyd Pique fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
1519*84e872a0SLloyd Pique assert(err == EAGAIN);
1520*84e872a0SLloyd Pique
1521*84e872a0SLloyd Pique client_disconnect_nocheck(c);
1522*84e872a0SLloyd Pique }
1523*84e872a0SLloyd Pique
TEST(send_overflow_disconnection)1524*84e872a0SLloyd Pique TEST(send_overflow_disconnection)
1525*84e872a0SLloyd Pique {
1526*84e872a0SLloyd Pique struct display *d;
1527*84e872a0SLloyd Pique char tmp;
1528*84e872a0SLloyd Pique int rpipe[2];
1529*84e872a0SLloyd Pique ssize_t ret;
1530*84e872a0SLloyd Pique
1531*84e872a0SLloyd Pique assert(pipe(rpipe) != -1);
1532*84e872a0SLloyd Pique
1533*84e872a0SLloyd Pique d = display_create();
1534*84e872a0SLloyd Pique
1535*84e872a0SLloyd Pique (void) client_create(d, send_overflow_client, &rpipe);
1536*84e872a0SLloyd Pique
1537*84e872a0SLloyd Pique /* Close write end of the pipe, so that the later read() call gets
1538*84e872a0SLloyd Pique * interrupted if the client dies */
1539*84e872a0SLloyd Pique close(rpipe[1]);
1540*84e872a0SLloyd Pique
1541*84e872a0SLloyd Pique /* Run the display until the client sends a `stop_display`, then
1542*84e872a0SLloyd Pique * send a resume message but don't actually look at new messages */
1543*84e872a0SLloyd Pique display_run(d);
1544*84e872a0SLloyd Pique display_post_resume_events(d);
1545*84e872a0SLloyd Pique wl_display_flush_clients(d->wl_display);
1546*84e872a0SLloyd Pique
1547*84e872a0SLloyd Pique /* Wait until all noop requests have been sent (read returns 1), or
1548*84e872a0SLloyd Pique * until client process aborts (read returns 0) */
1549*84e872a0SLloyd Pique do {
1550*84e872a0SLloyd Pique ret = read(rpipe[0], &tmp, sizeof(tmp));
1551*84e872a0SLloyd Pique } while (ret == -1 && errno == EINTR);
1552*84e872a0SLloyd Pique assert(ret != -1);
1553*84e872a0SLloyd Pique close(rpipe[0]);
1554*84e872a0SLloyd Pique
1555*84e872a0SLloyd Pique /* For a clean shutdown */
1556*84e872a0SLloyd Pique display_run(d);
1557*84e872a0SLloyd Pique
1558*84e872a0SLloyd Pique display_destroy(d);
1559*84e872a0SLloyd Pique }
1560*84e872a0SLloyd Pique
1561*84e872a0SLloyd Pique static void
registry_global_remove_before_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1562*84e872a0SLloyd Pique registry_global_remove_before_handle_global(void *data,
1563*84e872a0SLloyd Pique struct wl_registry *registry,
1564*84e872a0SLloyd Pique uint32_t id, const char *intf,
1565*84e872a0SLloyd Pique uint32_t ver)
1566*84e872a0SLloyd Pique {
1567*84e872a0SLloyd Pique uint32_t *id_ptr = data;
1568*84e872a0SLloyd Pique
1569*84e872a0SLloyd Pique if (strcmp(intf, wl_seat_interface.name) == 0) {
1570*84e872a0SLloyd Pique assert(*id_ptr == 0);
1571*84e872a0SLloyd Pique *id_ptr = id;
1572*84e872a0SLloyd Pique }
1573*84e872a0SLloyd Pique }
1574*84e872a0SLloyd Pique
1575*84e872a0SLloyd Pique static void
registry_global_remove_before_handle_global_remove(void * data,struct wl_registry * registry,uint32_t id)1576*84e872a0SLloyd Pique registry_global_remove_before_handle_global_remove(void *data,
1577*84e872a0SLloyd Pique struct wl_registry *registry,
1578*84e872a0SLloyd Pique uint32_t id)
1579*84e872a0SLloyd Pique {
1580*84e872a0SLloyd Pique uint32_t *id_ptr = data;
1581*84e872a0SLloyd Pique
1582*84e872a0SLloyd Pique if (*id_ptr == id) {
1583*84e872a0SLloyd Pique *id_ptr = 0;
1584*84e872a0SLloyd Pique }
1585*84e872a0SLloyd Pique }
1586*84e872a0SLloyd Pique
1587*84e872a0SLloyd Pique /* This listener expects a uint32_t user data pointer, sets it to the wl_seat
1588*84e872a0SLloyd Pique * global ID when receiving a "global" event, and sets it to zero when receiving
1589*84e872a0SLloyd Pique * a "global_remove" event. */
1590*84e872a0SLloyd Pique static const struct wl_registry_listener global_remove_before_registry_listener = {
1591*84e872a0SLloyd Pique registry_global_remove_before_handle_global,
1592*84e872a0SLloyd Pique registry_global_remove_before_handle_global_remove,
1593*84e872a0SLloyd Pique };
1594*84e872a0SLloyd Pique
1595*84e872a0SLloyd Pique static void
global_remove_before_client(void * data)1596*84e872a0SLloyd Pique global_remove_before_client(void *data)
1597*84e872a0SLloyd Pique {
1598*84e872a0SLloyd Pique struct client *c = client_connect();
1599*84e872a0SLloyd Pique struct wl_registry *registry;
1600*84e872a0SLloyd Pique uint32_t global_id = 0, saved_global_id;
1601*84e872a0SLloyd Pique struct wl_seat *seat;
1602*84e872a0SLloyd Pique int ret;
1603*84e872a0SLloyd Pique
1604*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1605*84e872a0SLloyd Pique wl_registry_add_listener(registry,
1606*84e872a0SLloyd Pique &global_remove_before_registry_listener,
1607*84e872a0SLloyd Pique &global_id);
1608*84e872a0SLloyd Pique
1609*84e872a0SLloyd Pique ret = wl_display_roundtrip(c->wl_display);
1610*84e872a0SLloyd Pique assert(ret >= 0);
1611*84e872a0SLloyd Pique assert(global_id != 0);
1612*84e872a0SLloyd Pique saved_global_id = global_id;
1613*84e872a0SLloyd Pique
1614*84e872a0SLloyd Pique /* Wait for the compositor to remove the global */
1615*84e872a0SLloyd Pique assert(stop_display(c, 1) >= 0);
1616*84e872a0SLloyd Pique
1617*84e872a0SLloyd Pique /* Check binding still works after the global has been removed. Also
1618*84e872a0SLloyd Pique * check we get the global_remove event. */
1619*84e872a0SLloyd Pique seat = wl_registry_bind(registry, saved_global_id, &wl_seat_interface, 1);
1620*84e872a0SLloyd Pique ret = wl_display_roundtrip(c->wl_display);
1621*84e872a0SLloyd Pique assert(ret >= 0);
1622*84e872a0SLloyd Pique assert(global_id == 0);
1623*84e872a0SLloyd Pique
1624*84e872a0SLloyd Pique wl_seat_destroy(seat);
1625*84e872a0SLloyd Pique wl_registry_destroy(registry);
1626*84e872a0SLloyd Pique
1627*84e872a0SLloyd Pique client_disconnect(c);
1628*84e872a0SLloyd Pique }
1629*84e872a0SLloyd Pique
1630*84e872a0SLloyd Pique static void
registry_global_remove_after_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1631*84e872a0SLloyd Pique registry_global_remove_after_handle_global(void *data,
1632*84e872a0SLloyd Pique struct wl_registry *registry,
1633*84e872a0SLloyd Pique uint32_t id, const char *intf,
1634*84e872a0SLloyd Pique uint32_t ver)
1635*84e872a0SLloyd Pique {
1636*84e872a0SLloyd Pique /* Make sure the global isn't advertised anymore after being removed */
1637*84e872a0SLloyd Pique assert(strcmp(intf, wl_seat_interface.name) != 0);
1638*84e872a0SLloyd Pique }
1639*84e872a0SLloyd Pique
1640*84e872a0SLloyd Pique static const struct wl_registry_listener global_remove_after_registry_listener = {
1641*84e872a0SLloyd Pique registry_global_remove_after_handle_global,
1642*84e872a0SLloyd Pique NULL,
1643*84e872a0SLloyd Pique };
1644*84e872a0SLloyd Pique
1645*84e872a0SLloyd Pique static void
global_remove_after_client(void * data)1646*84e872a0SLloyd Pique global_remove_after_client(void *data)
1647*84e872a0SLloyd Pique {
1648*84e872a0SLloyd Pique struct client *c = client_connect();
1649*84e872a0SLloyd Pique struct wl_registry *registry;
1650*84e872a0SLloyd Pique uint32_t global_id = 0;
1651*84e872a0SLloyd Pique int ret;
1652*84e872a0SLloyd Pique
1653*84e872a0SLloyd Pique registry = wl_display_get_registry(c->wl_display);
1654*84e872a0SLloyd Pique wl_registry_add_listener(registry,
1655*84e872a0SLloyd Pique &global_remove_after_registry_listener,
1656*84e872a0SLloyd Pique &global_id);
1657*84e872a0SLloyd Pique
1658*84e872a0SLloyd Pique ret = wl_display_roundtrip(c->wl_display);
1659*84e872a0SLloyd Pique assert(ret >= 0);
1660*84e872a0SLloyd Pique
1661*84e872a0SLloyd Pique wl_registry_destroy(registry);
1662*84e872a0SLloyd Pique
1663*84e872a0SLloyd Pique client_disconnect(c);
1664*84e872a0SLloyd Pique }
1665*84e872a0SLloyd Pique
TEST(global_remove)1666*84e872a0SLloyd Pique TEST(global_remove)
1667*84e872a0SLloyd Pique {
1668*84e872a0SLloyd Pique struct display *d;
1669*84e872a0SLloyd Pique struct wl_global *global;
1670*84e872a0SLloyd Pique
1671*84e872a0SLloyd Pique d = display_create();
1672*84e872a0SLloyd Pique
1673*84e872a0SLloyd Pique global = wl_global_create(d->wl_display, &wl_seat_interface,
1674*84e872a0SLloyd Pique 1, d, bind_seat);
1675*84e872a0SLloyd Pique
1676*84e872a0SLloyd Pique /* Create a client before removing the global */
1677*84e872a0SLloyd Pique client_create_noarg(d, global_remove_before_client);
1678*84e872a0SLloyd Pique
1679*84e872a0SLloyd Pique display_run(d);
1680*84e872a0SLloyd Pique
1681*84e872a0SLloyd Pique wl_global_remove(global);
1682*84e872a0SLloyd Pique
1683*84e872a0SLloyd Pique /* Create another client after removing the global */
1684*84e872a0SLloyd Pique client_create_noarg(d, global_remove_after_client);
1685*84e872a0SLloyd Pique
1686*84e872a0SLloyd Pique display_resume(d);
1687*84e872a0SLloyd Pique
1688*84e872a0SLloyd Pique wl_global_destroy(global);
1689*84e872a0SLloyd Pique
1690*84e872a0SLloyd Pique display_destroy(d);
1691*84e872a0SLloyd Pique }
1692*84e872a0SLloyd Pique
1693*84e872a0SLloyd Pique static void
terminate_display(void * arg)1694*84e872a0SLloyd Pique terminate_display(void *arg)
1695*84e872a0SLloyd Pique {
1696*84e872a0SLloyd Pique struct wl_display *wl_display = arg;
1697*84e872a0SLloyd Pique wl_display_terminate(wl_display);
1698*84e872a0SLloyd Pique }
1699*84e872a0SLloyd Pique
TEST(no_source_terminate)1700*84e872a0SLloyd Pique TEST(no_source_terminate)
1701*84e872a0SLloyd Pique {
1702*84e872a0SLloyd Pique struct display *d;
1703*84e872a0SLloyd Pique struct wl_event_loop *loop;
1704*84e872a0SLloyd Pique
1705*84e872a0SLloyd Pique d = display_create();
1706*84e872a0SLloyd Pique loop = wl_display_get_event_loop(d->wl_display);
1707*84e872a0SLloyd Pique
1708*84e872a0SLloyd Pique wl_event_loop_add_idle(loop, terminate_display, d->wl_display);
1709*84e872a0SLloyd Pique
1710*84e872a0SLloyd Pique display_run(d);
1711*84e872a0SLloyd Pique display_destroy(d);
1712*84e872a0SLloyd Pique }
1713