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