test-compositor.c 14 KB

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