• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 Red Hat, Inc.
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 #include <assert.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <unistd.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <signal.h>
37 
38 #define WL_HIDE_DEPRECATED
39 
40 #include "test-runner.h"
41 #include "test-compositor.h"
42 
43 /* --- Protocol --- */
44 struct test_compositor;
45 
46 static const struct wl_message tc_requests[] = {
47 	/* this request serves as a barrier for synchronizing*/
48 	{ "stop_display", "u", NULL },
49 	{ "noop", "", NULL },
50 };
51 
52 static const struct wl_message tc_events[] = {
53 	{ "display_resumed", "", NULL }
54 };
55 
56 const struct wl_interface test_compositor_interface = {
57 	"test", 1,
58 	2, tc_requests,
59 	1, tc_events
60 };
61 
62 struct test_compositor_interface {
63 	void (*stop_display)(struct wl_client *client,
64 			     struct wl_resource *resource,
65 			     uint32_t num);
66 	void (*noop)(struct wl_client *client,
67 			     struct wl_resource *resource);
68 };
69 
70 struct test_compositor_listener {
71 	void (*display_resumed)(void *data, struct test_compositor *tc);
72 
73 };
74 
75 enum {
76 	STOP_DISPLAY = 0,
77 	TEST_NOOP = 1
78 };
79 
80 enum {
81 	DISPLAY_RESUMED = 0
82 };
83 
84 /* Since tests can run parallelly, we need unique socket names
85  * for each test, otherwise the test can fail on wl_display_add_socket. */
86 static const char *
get_socket_name(void)87 get_socket_name(void)
88 {
89 	struct timeval tv;
90 	static char retval[64];
91 
92 	gettimeofday(&tv, NULL);
93 	snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld",
94 		 getpid(), tv.tv_sec, tv.tv_usec);
95 
96 	return retval;
97 }
98 
99 static void
handle_client_destroy(void * data)100 handle_client_destroy(void *data)
101 {
102 	struct client_info *ci = data;
103 	struct display *d;
104 	siginfo_t status;
105 
106 	d = ci->display;
107 
108 	assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1);
109 
110 	switch (status.si_code) {
111 	case CLD_KILLED:
112 	case CLD_DUMPED:
113 		fprintf(stderr, "Client '%s' was killed by signal %d\n",
114 			ci->name, status.si_status);
115 		ci->exit_code = status.si_status;
116 		break;
117 	case CLD_EXITED:
118 		if (status.si_status != EXIT_SUCCESS)
119 			fprintf(stderr, "Client '%s' exited with code %d\n",
120 				ci->name, status.si_status);
121 
122 		ci->exit_code = status.si_status;
123 		break;
124 	}
125 
126 	++d->clients_terminated_no;
127 	if (d->clients_no == d->clients_terminated_no) {
128 		wl_display_terminate(d->wl_display);
129 	}
130 
131 	/* the clients are not removed from the list, because
132 	 * at the end of the test we check the exit codes of all
133 	 * clients. In the case that the test would go through
134 	 * the clients list manually, zero out the wl_client as a sign
135 	 * that the client is not running anymore */
136 }
137 
138 /**
139  * Check client's state and terminate display when all clients exited
140  */
141 static void
client_destroyed(struct wl_listener * listener,void * data)142 client_destroyed(struct wl_listener *listener, void *data)
143 {
144 	struct client_info *ci;
145 	struct display *d;
146 	struct wl_event_loop *loop;
147 
148 	/* Wait for client in an idle handler to avoid blocking the actual
149 	 * client destruction (fd close etc. */
150 	ci = wl_container_of(listener, ci, destroy_listener);
151 	d = ci->display;
152 	loop = wl_display_get_event_loop(d->wl_display);
153 	wl_event_loop_add_idle(loop, handle_client_destroy, ci);
154 
155 	ci->wl_client = NULL;
156 }
157 
158 static void
run_client(void (* client_main)(void * data),void * data,int wayland_sock,int client_pipe)159 run_client(void (*client_main)(void *data), void *data,
160 	   int wayland_sock, int client_pipe)
161 {
162 	char s[8];
163 	int cur_fds;
164 	int can_continue = 0;
165 
166 	/* Wait until display signals that client can continue */
167 	assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int));
168 
169 	if (can_continue == 0)
170 		abort(); /* error in parent */
171 
172 	/* for wl_display_connect() */
173 	snprintf(s, sizeof s, "%d", wayland_sock);
174 	setenv("WAYLAND_SOCKET", s, 0);
175 
176 	cur_fds = count_open_fds();
177 
178 	client_main(data);
179 
180 	/* Clients using wl_display_connect() will end up closing the socket
181 	 * passed in through the WAYLAND_SOCKET environment variable. When
182 	 * doing this, it clears the environment variable, so if it's been
183 	 * unset, then we assume the client consumed the file descriptor and
184 	 * do not count it towards leak checking. */
185 	if (!getenv("WAYLAND_SOCKET"))
186 		cur_fds--;
187 
188 	check_fd_leaks(cur_fds);
189 }
190 
191 static struct client_info *
display_create_client(struct display * d,void (* client_main)(void * data),void * data,const char * name)192 display_create_client(struct display *d,
193 		      void (*client_main)(void *data),
194 		      void *data,
195 		      const char *name)
196 {
197 	int pipe_cli[2];
198 	int sock_wayl[2];
199 	pid_t pid;
200 	int can_continue = 0;
201 	struct client_info *cl;
202 
203 	assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
204 	assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
205 	       && "Failed creating socket pair");
206 
207 	pid = fork();
208 	assert(pid != -1 && "Fork failed");
209 
210 	if (pid == 0) {
211 		close(sock_wayl[1]);
212 		close(pipe_cli[1]);
213 
214 		run_client(client_main, data, sock_wayl[0], pipe_cli[0]);
215 
216 		close(sock_wayl[0]);
217 		close(pipe_cli[0]);
218 
219 		exit(0);
220 	}
221 
222 	close(sock_wayl[0]);
223 	close(pipe_cli[0]);
224 
225 	cl = calloc(1, sizeof(struct client_info));
226 	assert(cl && "Out of memory");
227 
228 	wl_list_insert(&d->clients, &cl->link);
229 
230 	cl->display = d;
231 	cl->name = name;
232 	cl->pid = pid;
233 	cl->pipe = pipe_cli[1];
234 	cl->destroy_listener.notify = &client_destroyed;
235 
236 	cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
237 	if (!cl->wl_client) {
238 		int ret;
239 
240 		/* abort the client */
241 		ret = write(cl->pipe, &can_continue, sizeof(int));
242 		assert(ret == sizeof(int) && "aborting the client failed");
243 		assert(0 && "Couldn't create wayland client");
244 	}
245 
246 	wl_client_add_destroy_listener(cl->wl_client,
247 				       &cl->destroy_listener);
248 
249 	++d->clients_no;
250 
251 	return cl;
252 }
253 
254 struct client_info *
client_create_with_name(struct display * d,void (* client_main)(void * data),void * data,const char * name)255 client_create_with_name(struct display *d,
256 			void (*client_main)(void *data), void *data,
257 			const char *name)
258 {
259 	int can_continue = 1;
260 	struct client_info *cl = display_create_client(d,
261 						       client_main, data,
262 						       name);
263 
264 	/* let the show begin! */
265 	assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int));
266 
267 	return cl;
268 }
269 
270 /* wfr = waiting for resume */
271 struct wfr {
272 	struct wl_resource *resource;
273 	struct wl_list link;
274 };
275 
276 static void
handle_stop_display(struct wl_client * client,struct wl_resource * resource,uint32_t num)277 handle_stop_display(struct wl_client *client,
278 		    struct wl_resource *resource, uint32_t num)
279 {
280 	struct display *d = wl_resource_get_user_data(resource);
281 	struct wfr *wfr;
282 
283 	assert(d->wfr_num < num
284 	       && "test error: Too many clients sent stop_display request");
285 
286 	++d->wfr_num;
287 
288 	wfr = malloc(sizeof *wfr);
289 	if (!wfr) {
290 		wl_client_post_no_memory(client);
291 		assert(0 && "Out of memory");
292 	}
293 
294 	wfr->resource = resource;
295 	wl_list_insert(&d->waiting_for_resume, &wfr->link);
296 
297 	if (d->wfr_num == num)
298 		wl_display_terminate(d->wl_display);
299 }
300 
301 static void
handle_noop(struct wl_client * client,struct wl_resource * resource)302 handle_noop(struct wl_client *client, struct wl_resource *resource)
303 {
304 	(void)client;
305 	(void)resource;
306 }
307 
308 static const struct test_compositor_interface tc_implementation = {
309 	handle_stop_display,
310 	handle_noop,
311 };
312 
313 static void
tc_bind(struct wl_client * client,void * data,uint32_t ver,uint32_t id)314 tc_bind(struct wl_client *client, void *data,
315 	uint32_t ver, uint32_t id)
316 {
317 	struct wl_resource *res;
318 
319 	res = wl_resource_create(client, &test_compositor_interface, ver, id);
320 	if (!res) {
321 		wl_client_post_no_memory(client);
322 		assert(0 && "Out of memory");
323 	}
324 
325 	wl_resource_set_implementation(res, &tc_implementation, data, NULL);
326 }
327 
328 struct display *
display_create(void)329 display_create(void)
330 {
331 	struct display *d = NULL;
332 	struct wl_global *g;
333 	const char *socket_name;
334 	int stat = 0;
335 
336 	d = calloc(1, sizeof *d);
337 	assert(d && "Out of memory");
338 
339 	d->wl_display = wl_display_create();
340 	assert(d->wl_display && "Creating display failed");
341 
342 	/* hope the path won't be longer than 108 ... */
343 	socket_name = get_socket_name();
344 	stat = wl_display_add_socket(d->wl_display, socket_name);
345 	assert(stat == 0 && "Failed adding socket");
346 
347 	wl_list_init(&d->clients);
348 	d->clients_no = d->clients_terminated_no = 0;
349 
350 	wl_list_init(&d->waiting_for_resume);
351 	d->wfr_num = 0;
352 
353 	g = wl_global_create(d->wl_display, &test_compositor_interface,
354 			     1, d, tc_bind);
355 	assert(g && "Creating test global failed");
356 
357 	return d;
358 }
359 
360 void
display_run(struct display * d)361 display_run(struct display *d)
362 {
363 	assert(d->wfr_num == 0
364 	       && "test error: Have waiting clients. Use display_resume.");
365 	wl_display_run(d->wl_display);
366 }
367 
368 void
display_post_resume_events(struct display * d)369 display_post_resume_events(struct display *d)
370 {
371 	struct wfr *wfr, *next;
372 
373 	assert(d->wfr_num > 0 && "test error: No clients waiting.");
374 
375 	wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) {
376 		wl_resource_post_event(wfr->resource, DISPLAY_RESUMED);
377 		wl_list_remove(&wfr->link);
378 		free(wfr);
379 	}
380 
381 	assert(wl_list_empty(&d->waiting_for_resume));
382 	d->wfr_num = 0;
383 }
384 
385 void
display_resume(struct display * d)386 display_resume(struct display *d)
387 {
388 	display_post_resume_events(d);
389 	wl_display_run(d->wl_display);
390 }
391 
392 void
display_destroy(struct display * d)393 display_destroy(struct display *d)
394 {
395 	struct client_info *cl, *next;
396 	int failed = 0;
397 
398 	assert(d->wfr_num == 0
399 	       && "test error: Didn't you forget to call display_resume?");
400 
401 	wl_list_for_each_safe(cl, next, &d->clients, link) {
402 		assert(cl->wl_client == NULL);
403 
404 		if (cl->exit_code != 0) {
405 			++failed;
406 			fprintf(stderr, "Client '%s' failed\n", cl->name);
407 		}
408 
409 		close(cl->pipe);
410 		free(cl);
411 	}
412 
413 	wl_display_destroy(d->wl_display);
414 	free(d);
415 
416 	if (failed) {
417 		fprintf(stderr, "%d child(ren) failed\n", failed);
418 		abort();
419 	}
420 }
421 
422 /*
423  * --- Client helper functions ---
424  */
425 static void
handle_display_resumed(void * data,struct test_compositor * tc)426 handle_display_resumed(void *data, struct test_compositor *tc)
427 {
428 	struct client *c = data;
429 
430 	c->display_stopped = 0;
431 }
432 
433 static const struct test_compositor_listener tc_listener = {
434 	handle_display_resumed
435 };
436 
437 static void
registry_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)438 registry_handle_globals(void *data, struct wl_registry *registry,
439 			uint32_t id, const char *intf, uint32_t ver)
440 {
441 	struct client *c = data;
442 
443 	if (strcmp(intf, "test") != 0)
444 		return;
445 
446 	c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
447 	assert(c->tc && "Failed binding to registry");
448 
449 	wl_proxy_add_listener((struct wl_proxy *) c->tc,
450 			      (void *) &tc_listener, c);
451 }
452 
453 static const struct wl_registry_listener registry_listener =
454 {
455 	registry_handle_globals,
456 	NULL
457 };
458 
client_connect()459 struct client *client_connect()
460 {
461 	struct wl_registry *reg;
462 	struct client *c = calloc(1, sizeof *c);
463 	assert(c && "Out of memory");
464 
465 	c->wl_display = wl_display_connect(NULL);
466 	assert(c->wl_display && "Failed connecting to display");
467 
468 	/* create test_compositor proxy. Do it with temporary
469 	 * registry so that client can define it's own listener later */
470 	reg = wl_display_get_registry(c->wl_display);
471 	assert(reg);
472 	wl_registry_add_listener(reg, &registry_listener, c);
473 	wl_display_roundtrip(c->wl_display);
474 	assert(c->tc);
475 
476 	wl_registry_destroy(reg);
477 
478 	return c;
479 }
480 
481 static void
check_error(struct wl_display * display)482 check_error(struct wl_display *display)
483 {
484 	uint32_t ec, id;
485 	const struct wl_interface *intf;
486 	int err;
487 
488 	err = wl_display_get_error(display);
489 	/* write out message about protocol error */
490 	if (err == EPROTO) {
491 		ec = wl_display_get_protocol_error(display, &intf, &id);
492 		fprintf(stderr, "Client: Got protocol error %u on interface %s"
493 				" (object %u)\n", ec, intf->name, id);
494 	}
495 
496 	if (err) {
497 		fprintf(stderr, "Client error: %s\n", strerror(err));
498 		abort();
499 	}
500 }
501 
502 void
client_disconnect(struct client * c)503 client_disconnect(struct client *c)
504 {
505 	/* check for errors */
506 	check_error(c->wl_display);
507 
508 	wl_proxy_destroy((struct wl_proxy *) c->tc);
509 	wl_display_disconnect(c->wl_display);
510 	free(c);
511 }
512 
513 /* num is number of clients that requests to stop display.
514  * Display is stopped after it receives num STOP_DISPLAY requests */
515 int
stop_display(struct client * c,int num)516 stop_display(struct client *c, int num)
517 {
518 	int n = 0;
519 
520 	c->display_stopped = 1;
521 	wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num);
522 
523 	while (c->display_stopped && n >= 0) {
524 		n = wl_display_dispatch(c->wl_display);
525 	}
526 
527 	return n;
528 }
529 
530 void
noop_request(struct client * c)531 noop_request(struct client *c)
532 {
533 	wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP);
534 }
535