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