"Fossies" - the Fresh Open Source Software Archive

Member "wayland-1.18.0/tests/display-test.c" (11 Feb 2020, 39427 Bytes) of package /linux/misc/wayland-1.18.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "display-test.c": 1.17.0_vs_1.18.0.

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