summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2012-02-29 11:07:48 -0500
committerKristian Høgsberg <krh@bitplanet.net>2012-02-29 11:07:48 -0500
commitb26774da5b907a71aa7c72ee1feb6dcde92b9fcb (patch)
tree20baf988f33a0ddde7f4f1df2a810bc7f140f1db
parentbf53f2033d0f39bab59da783f5b13f9e3bfe7073 (diff)
Don't block when flushing a full protocol buffer
In case the client isn't responding, this will block the compositor. Instead we flush with MSG_DONTWAIT, which lets us fill up the kernel buffer as much as we can (after not returning EPOLLOUT anymore it still can take 80k more), and then disconnect the client if we get EAGAIN.
-rw-r--r--src/connection.c27
-rw-r--r--src/wayland-client.c5
-rw-r--r--src/wayland-private.h6
-rw-r--r--src/wayland-server.c16
4 files changed, 39 insertions, 15 deletions
diff --git a/src/connection.c b/src/connection.c
index 4ac5bf8..6bcc91a 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -269,7 +269,8 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask)
msg.msg_flags = 0;
do {
- len = sendmsg(connection->fd, &msg, MSG_NOSIGNAL);
+ len = sendmsg(connection->fd, &msg,
+ MSG_NOSIGNAL | MSG_DONTWAIT);
} while (len < 0 && errno == EINTR);
if (len == -1 && errno == EPIPE) {
@@ -326,13 +327,14 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask)
return connection->in.head - connection->in.tail;
}
-void
+int
wl_connection_write(struct wl_connection *connection,
const void *data, size_t count)
{
if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data))
- wl_connection_data(connection, WL_CONNECTION_WRITABLE);
+ if (wl_connection_data(connection, WL_CONNECTION_WRITABLE))
+ return -1;
wl_buffer_put(&connection->out, data, count);
@@ -343,17 +345,22 @@ wl_connection_write(struct wl_connection *connection,
connection->data);
connection->write_signalled = 1;
}
+
+ return 0;
}
-static void
+static int
wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count)
{
if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data))
- wl_connection_data(connection, WL_CONNECTION_WRITABLE);
+ if (wl_connection_data(connection, WL_CONNECTION_WRITABLE))
+ return -1;
wl_buffer_put(&connection->out, data, count);
+
+ return 0;
}
static int
@@ -734,22 +741,24 @@ wl_closure_invoke(struct wl_closure *closure,
ffi_call(&closure->cif, func, &result, closure->args);
}
-void
+int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
{
uint32_t size;
size = closure->start[1] >> 16;
- wl_connection_write(connection, closure->start, size);
+
+ return wl_connection_write(connection, closure->start, size);
}
-void
+int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
{
uint32_t size;
size = closure->start[1] >> 16;
- wl_connection_queue(connection, closure->start, size);
+
+ return wl_connection_queue(connection, closure->start, size);
}
void
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 9656cb5..498a429 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -203,7 +203,10 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
abort();
}
- wl_closure_send(closure, proxy->display->connection);
+ if (wl_closure_send(closure, proxy->display->connection)) {
+ fprintf(stderr, "Error sending request: %m\n");
+ abort();
+ }
if (wl_debug)
wl_closure_print(closure, &proxy->object, true);
diff --git a/src/wayland-private.h b/src/wayland-private.h
index dee5ed1..bdeafd4 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -65,7 +65,7 @@ void wl_connection_destroy(struct wl_connection *connection);
void wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
void wl_connection_consume(struct wl_connection *connection, size_t size);
int wl_connection_data(struct wl_connection *connection, uint32_t mask);
-void wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
+int wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
struct wl_closure *
wl_connection_vmarshal(struct wl_connection *connection,
@@ -81,9 +81,9 @@ wl_connection_demarshal(struct wl_connection *connection,
void
wl_closure_invoke(struct wl_closure *closure,
struct wl_object *target, void (*func)(void), void *data);
-void
+int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
-void
+int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
void
wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index bf81334..c70e411 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -88,6 +88,14 @@ struct wl_global {
static int wl_debug = 0;
+static void
+destroy_client(void *data)
+{
+ struct wl_client *client = data;
+
+ wl_client_destroy(client);
+}
+
WL_EXPORT void
wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
{
@@ -104,7 +112,9 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
if (closure == NULL)
return;
- wl_closure_send(closure, resource->client->connection);
+ if (wl_closure_send(closure, resource->client->connection))
+ wl_event_loop_add_idle(resource->client->display->loop,
+ destroy_client, resource->client);
if (wl_debug)
wl_closure_print(closure, object, true);
@@ -129,7 +139,9 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
if (closure == NULL)
return;
- wl_closure_queue(closure, resource->client->connection);
+ if (wl_closure_queue(closure, resource->client->connection))
+ wl_event_loop_add_idle(resource->client->display->loop,
+ destroy_client, resource->client);
if (wl_debug)
wl_closure_print(closure, object, true);