[RFC wayland 16/18] connection: Use bulk transfers for fd_static on remote connections

Derek Foreman derekf at osg.samsung.com
Tue Feb 9 16:56:03 UTC 2016


This copies the contents of keymaps over the network for remote
connections. Any future user of fd_static should Just Work too.

Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
---
 src/connection.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/wayland-private.h |  2 ++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/connection.c b/src/connection.c
index 8a44806..c1f65a4 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -562,9 +562,12 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
 	}
 
 	memcpy(closure->args, args, count * sizeof *args);
+	closure->n_remote_fds = 0;
 
 	signature = message->signature;
 	for (i = 0; i < count; i++) {
+		bool has_bulk = false;
+
 		signature = get_next_argument(signature, &arg);
 
 		switch (arg.type) {
@@ -592,12 +595,25 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
 				goto err_null;
 			break;
 		case 'H':
+			has_bulk = true;
 		case 'h':
 			fd = args[i].h;
 			dup_fd = wl_os_dupfd_cloexec(fd, 0);
 			if (dup_fd < 0)
 				wl_abort("dup failed: %s\n", strerror(errno));
 			closure->args[i].h = dup_fd;
+			if (sender->remote && has_bulk) {
+				/* Dupe it again for sending its data later,
+				 * the other dupe will be automatically closed
+				 * on connection flush.
+				 */
+				dup_fd = wl_os_dupfd_cloexec(dup_fd, 0);
+				if (dup_fd < 0)
+					wl_abort("dup failed: %s\n",
+						 strerror(errno));
+				closure->remote_fds[closure->n_remote_fds] = dup_fd;
+				closure->n_remote_fds++;
+			}
 			break;
 		default:
 			wl_abort("unhandled format code: '%c'\n", arg.type);
@@ -640,7 +656,7 @@ wl_connection_demarshal(struct wl_connection *connection,
 			const struct wl_message *message)
 {
 	uint32_t *p, *next, *end, length, id;
-	int fd;
+	int fd, fdi;
 	char *s;
 	unsigned int i, count, num_arrays;
 	const char *signature;
@@ -664,6 +680,8 @@ wl_connection_demarshal(struct wl_connection *connection,
 		return NULL;
 	}
 
+	closure->n_remote_fds = 0;
+
 	array_extra = closure->extra;
 	p = (uint32_t *)(closure->extra + num_arrays);
 	end = p + size / sizeof *p;
@@ -674,6 +692,7 @@ wl_connection_demarshal(struct wl_connection *connection,
 
 	signature = message->signature;
 	for (i = 0; i < count; i++) {
+		bool has_bulk = false;
 		signature = get_next_argument(signature, &arg);
 
 		if (arg.type != 'h' && p + 1 > end) {
@@ -779,7 +798,16 @@ wl_connection_demarshal(struct wl_connection *connection,
 			p = next;
 			break;
 		case 'H':
+			has_bulk = true;
 		case 'h':
+			if (connection->remote) {
+				closure->args[i].h = wl_os_create_anonymous_file(0);
+				if (has_bulk) {
+					closure->remote_fds[closure->n_remote_fds] = closure->args[i].h;
+					closure->n_remote_fds++;
+				}
+				break;
+			}
 			if (connection->fds_in.tail == connection->fds_in.head) {
 				wl_log("file descriptor expected, "
 				       "object (%d), message %s(%s)\n",
@@ -804,6 +832,11 @@ wl_connection_demarshal(struct wl_connection *connection,
 
 	wl_connection_consume(connection, size);
 
+	for (fdi = 0; fdi < closure->n_remote_fds; fdi++)
+		wl_connection_get_bulk_data(connection, closure->remote_fds[fdi]);
+
+	/* we don't want to clean them up in destroy... */
+	closure->n_remote_fds = 0;
 	return closure;
 
  err:
@@ -1215,6 +1248,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
 	uint32_t buffer_size;
 	uint32_t *buffer;
 	int result;
+	int i;
 
 	if (copy_fds_to_connection(closure, connection))
 		return -1;
@@ -1233,6 +1267,20 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
 	result = wl_connection_write(connection, buffer, size);
 	free(buffer);
 
+	if (result < 0 || !closure->n_remote_fds)
+		return result;
+
+	connection->want_flush = 1;
+	wl_connection_flush(connection);
+
+	for (i = 0; i < closure->n_remote_fds; i++) {
+		result = wl_connection_put_bulk_data(connection,
+					    closure->remote_fds[i]);
+
+		if (result < 0)
+			break;
+	}
+
 	return result;
 }
 
@@ -1261,6 +1309,11 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
 	result = wl_connection_queue(connection, buffer, size);
 	free(buffer);
 
+	if (closure->n_remote_fds) {
+		wl_log("Unable to queue closure with remote fds\n");
+		return -1;
+	}
+
 	return result;
 }
 
@@ -1335,5 +1388,10 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
 void
 wl_closure_destroy(struct wl_closure *closure)
 {
+	int i;
+
+	for (i = 0; i < closure->n_remote_fds; i++)
+		close(closure->remote_fds[i]);
+
 	free(closure);
 }
diff --git a/src/wayland-private.h b/src/wayland-private.h
index be41e83..f5d6100 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -150,6 +150,8 @@ struct wl_closure {
 	uint32_t opcode;
 	uint32_t sender_id;
 	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	int n_remote_fds;
+	int remote_fds[WL_CLOSURE_MAX_ARGS];
 	struct wl_list link;
 	struct wl_proxy *proxy;
 	struct wl_array extra[0];
-- 
2.7.0



More information about the wayland-devel mailing list