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.
This commit is contained in:
Kristian Høgsberg 2012-02-29 11:07:48 -05:00
parent bf53f2033d
commit b26774da5b
4 changed files with 39 additions and 15 deletions

View file

@ -269,7 +269,8 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask)
msg.msg_flags = 0; msg.msg_flags = 0;
do { do {
len = sendmsg(connection->fd, &msg, MSG_NOSIGNAL); len = sendmsg(connection->fd, &msg,
MSG_NOSIGNAL | MSG_DONTWAIT);
} while (len < 0 && errno == EINTR); } while (len < 0 && errno == EINTR);
if (len == -1 && errno == EPIPE) { 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; return connection->in.head - connection->in.tail;
} }
void int
wl_connection_write(struct wl_connection *connection, wl_connection_write(struct wl_connection *connection,
const void *data, size_t count) const void *data, size_t count)
{ {
if (connection->out.head - connection->out.tail + if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data)) 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); wl_buffer_put(&connection->out, data, count);
@ -343,17 +345,22 @@ wl_connection_write(struct wl_connection *connection,
connection->data); connection->data);
connection->write_signalled = 1; connection->write_signalled = 1;
} }
return 0;
} }
static void static int
wl_connection_queue(struct wl_connection *connection, wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count) const void *data, size_t count)
{ {
if (connection->out.head - connection->out.tail + if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data)) 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); wl_buffer_put(&connection->out, data, count);
return 0;
} }
static int static int
@ -734,22 +741,24 @@ wl_closure_invoke(struct wl_closure *closure,
ffi_call(&closure->cif, func, &result, closure->args); ffi_call(&closure->cif, func, &result, closure->args);
} }
void int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
{ {
uint32_t size; uint32_t size;
size = closure->start[1] >> 16; 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) wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
{ {
uint32_t size; uint32_t size;
size = closure->start[1] >> 16; size = closure->start[1] >> 16;
wl_connection_queue(connection, closure->start, size);
return wl_connection_queue(connection, closure->start, size);
} }
void void

View file

@ -203,7 +203,10 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
abort(); 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) if (wl_debug)
wl_closure_print(closure, &proxy->object, true); wl_closure_print(closure, &proxy->object, true);

View file

@ -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_copy(struct wl_connection *connection, void *data, size_t size);
void wl_connection_consume(struct wl_connection *connection, 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); 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 * struct wl_closure *
wl_connection_vmarshal(struct wl_connection *connection, wl_connection_vmarshal(struct wl_connection *connection,
@ -81,9 +81,9 @@ wl_connection_demarshal(struct wl_connection *connection,
void void
wl_closure_invoke(struct wl_closure *closure, wl_closure_invoke(struct wl_closure *closure,
struct wl_object *target, void (*func)(void), void *data); struct wl_object *target, void (*func)(void), void *data);
void int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection); wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
void int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
void void
wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send); wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send);

View file

@ -88,6 +88,14 @@ struct wl_global {
static int wl_debug = 0; static int wl_debug = 0;
static void
destroy_client(void *data)
{
struct wl_client *client = data;
wl_client_destroy(client);
}
WL_EXPORT void WL_EXPORT void
wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) 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) if (closure == NULL)
return; 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) if (wl_debug)
wl_closure_print(closure, object, true); wl_closure_print(closure, object, true);
@ -129,7 +139,9 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
if (closure == NULL) if (closure == NULL)
return; 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) if (wl_debug)
wl_closure_print(closure, object, true); wl_closure_print(closure, object, true);