summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2015-12-28 14:33:36 +0800
committerJonas Ådahl <jadahl@gmail.com>2016-01-16 16:37:37 +0800
commitc6437817dd9bbb2fd1027a103e77e238ad5e5ddb (patch)
treeac7a72599a7b6140d33117f01c24611eb987fdaa
parent046012a6cf1a50e1de2c73cf5a29098453b0171f (diff)
downloadwayland-c6437817dd9bbb2fd1027a103e77e238ad5e5ddb.tar.gz
tests: Test that one can fetch the protocol error after EPIPE
If a client is terminated due to some reason, it should always be possible to retrieve protocol error associated with the termination. Test that, while either using the dispatch helpers (wl_display_dispatch(_queue)() or the prepare read API, it should be possible to retrieve the error after EPIPE. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
-rw-r--r--tests/display-test.c178
1 files changed, 169 insertions, 9 deletions
diff --git a/tests/display-test.c b/tests/display-test.c
index f931c13..0d25ca3 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -24,6 +24,7 @@
* SOFTWARE.
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -35,6 +36,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
+#include <poll.h>
#include "wayland-private.h"
#include "wayland-server.h"
@@ -135,15 +137,12 @@ client_get_seat(struct client *c)
}
static void
-check_for_error(struct client *c, struct wl_proxy *proxy)
+check_pending_error(struct client *c, struct wl_proxy *proxy)
{
uint32_t ec, id;
int err;
const struct wl_interface *intf;
- /* client should be disconnected */
- assert(wl_display_roundtrip(c->wl_display) == -1);
-
err = wl_display_get_error(c->wl_display);
assert(err == EPROTO);
@@ -154,20 +153,40 @@ check_for_error(struct client *c, struct wl_proxy *proxy)
}
static void
-bind_seat(struct wl_client *client, void *data,
- uint32_t vers, uint32_t id)
+check_for_error(struct client *c, struct wl_proxy *proxy)
+{
+ /* client should be disconnected */
+ assert(wl_display_roundtrip(c->wl_display) == -1);
+
+ check_pending_error(c, proxy);
+}
+
+static struct client_info *
+find_client_info(struct display *d, struct wl_client *client)
{
- struct display *d = data;
struct client_info *ci;
- struct wl_resource *res;
/* find the right client_info struct and save the
* resource as its data, so that we can use it later */
wl_list_for_each(ci, &d->clients, link) {
if (ci->wl_client == client)
- break;
+ return ci;
}
+ return NULL;
+}
+
+static void
+bind_seat(struct wl_client *client, void *data,
+ uint32_t vers, uint32_t id)
+{
+ struct display *d = data;
+ struct client_info *ci;
+ struct wl_resource *res;
+
+ ci = find_client_info(d, client);
+ assert(ci);
+
res = wl_resource_create(client, &wl_seat_interface, vers, id);
assert(res);
@@ -609,3 +628,144 @@ TEST(threading_read_after_error_tst)
display_destroy(d);
}
+
+static void
+wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy)
+{
+ int ret;
+
+ while (true) {
+ /* Dispatching should eventually hit the protocol error before
+ * any other error. */
+ ret = wl_display_dispatch(c->wl_display);
+ if (ret == 0) {
+ continue;
+ } else {
+ assert(errno == EPROTO);
+ break;
+ }
+ }
+
+ check_pending_error(c, proxy);
+}
+
+static void
+wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy)
+{
+ int ret = 0;
+ struct pollfd pfd[2];
+
+ while (true) {
+ while (wl_display_prepare_read(c->wl_display) != 0 &&
+ errno == EAGAIN) {
+ assert(wl_display_dispatch_pending(c->wl_display) >= 0);
+ }
+
+ /* Flush may fail due to EPIPE if the connection is broken, but
+ * this must not set a fatal display error because that would
+ * result in it being impossible to read a potential protocol
+ * error. */
+ do {
+ ret = wl_display_flush(c->wl_display);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+ assert(ret >= 0 || errno == EPIPE);
+ assert(wl_display_get_error(c->wl_display) == 0);
+
+ pfd[0].fd = wl_display_get_fd(c->wl_display);
+ pfd[0].events = POLLIN;
+ do {
+ ret = poll(pfd, 1, -1);
+ } while (ret == -1 && errno == EINTR);
+ assert(ret != -1);
+
+ /* We should always manage to read the error before the EPIPE
+ * comes this way. */
+ assert(wl_display_read_events(c->wl_display) == 0);
+
+ /* Dispatching should eventually hit the protocol error before
+ * any other error. */
+ ret = wl_display_dispatch_pending(c->wl_display);
+ if (ret == 0) {
+ continue;
+ } else {
+ assert(errno == EPROTO);
+ break;
+ }
+ }
+
+ check_pending_error(c, proxy);
+}
+
+static void
+check_error_after_epipe(void *data)
+{
+ bool use_dispatch_helpers = *(bool *) data;
+ struct client *client;
+ struct wl_seat *seat;
+ struct wl_callback *callback;
+
+ client = client_connect();
+
+ /* This will, according to the implementation below, cause the server
+ * to post an error. */
+ seat = client_get_seat(client);
+ wl_display_flush(client->wl_display);
+
+ /* The server will not actually destroy the client until it receives
+ * input, so send something to trigger the client destruction. */
+ callback = wl_display_sync(client->wl_display);
+ wl_callback_destroy(callback);
+
+ /* Sleep some to give the server a chance to react and destroy the
+ * client. */
+ test_usleep(200000);
+
+ /* Wait for the protocol error and check that we reached it before
+ * EPIPE. */
+ if (use_dispatch_helpers) {
+ wait_for_error_using_dispatch(client, (struct wl_proxy *) seat);
+ } else {
+ wait_for_error_using_prepare_read(client,
+ (struct wl_proxy *) seat);
+ }
+
+ wl_seat_destroy(seat);
+ client_disconnect_nocheck(client);
+}
+
+static void
+bind_seat_and_post_error(struct wl_client *client, void *data,
+ uint32_t version, uint32_t id)
+{
+ struct display *d = data;
+ struct client_info *ci;
+ struct wl_resource *resource;
+
+ ci = find_client_info(d, client);
+ assert(ci);
+
+ resource = wl_resource_create(client, &wl_seat_interface, version, id);
+ assert(resource);
+ ci->data = resource;
+
+ wl_resource_post_error(ci->data, 23, "Dummy error");
+}
+
+TEST(error_code_after_epipe)
+{
+ struct display *d = display_create();
+ bool use_dispatch_helpers;
+
+ wl_global_create(d->wl_display, &wl_seat_interface,
+ 1, d, bind_seat_and_post_error);
+
+ use_dispatch_helpers = true;
+ client_create(d, check_error_after_epipe, &use_dispatch_helpers);
+ display_run(d);
+
+ use_dispatch_helpers = false;
+ client_create(d, check_error_after_epipe, &use_dispatch_helpers);
+ display_run(d);
+
+ display_destroy(d);
+}