[RFC wayland 1/2] server: implement intact resources

Marek Chalupa mchqwerty at gmail.com
Thu Mar 19 01:11:47 PDT 2015


When server looses some capability (like pointer or keyboard),
it takes some time to get this information to clients.
When client sends request with new_id argument to the object
that has been just destroyed on server-side (client
does not know about it yet), we still have to create the resource.
If we wouldn't do it then the client will get invalid id error once it
tries to use the new object. But if we create it, then we have to
take care that all the requests but destructor are ignored,
because we do not have the server-side object anymore.
(eventually, client will destroy the resource, because
it will get the information about server-side object destruction)

This patch solves this ugly race by adding wl_resource_set_intact()
function that marks the resource as intact. When resource is intact
it ignores all requests and events but destructors. The trick is in
adding flag into the request's siganture that says: "hey! I'm
destructor". Server then can skip non-destructor actions on intact
resource.

Programmer then can mark newly created resource as intact when
this race come up instead of defining new implementation of
resource just for this rare case.

Signed-off-by: Marek Chalupa <mchqwerty at gmail.com>
---
 src/connection.c      | 17 ++++++++++++++---
 src/scanner.c         |  5 +++++
 src/wayland-client.c  |  6 +++---
 src/wayland-private.h |  3 ++-
 src/wayland-server.c  | 41 ++++++++++++++++++++++++++++++++++-------
 src/wayland-server.h  |  6 ++++++
 6 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index 2545194..a8fab12 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -415,6 +415,9 @@ get_next_argument(const char *signature, struct argument_details *details)
 	details->nullable = 0;
 	for(; *signature; ++signature) {
 		switch(*signature) {
+		case 'D':
+			/* skip destructor flag */
+			break;
 		case 'i':
 		case 'u':
 		case 'f':
@@ -457,8 +460,14 @@ int
 wl_message_get_since(const struct wl_message *message)
 {
 	int since;
+	const char *sig = message->signature;
+
+	/* destructor flag is always the first letter in
+	 * signature */
+	if (*sig == 'D')
+		++sig;
 
-	since = atoi(message->signature);
+	since = atoi(sig);
 
 	if (since == 0)
 		since = 1;
@@ -1175,7 +1184,8 @@ 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)
+wl_closure_print(struct wl_closure *closure, struct wl_object *target,
+		 int send, int intact)
 {
 	int i;
 	struct argument_details arg;
@@ -1186,9 +1196,10 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
 	clock_gettime(CLOCK_REALTIME, &tp);
 	time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
 
-	fprintf(stderr, "[%10.3f] %s%s@%u.%s(",
+	fprintf(stderr, "[%10.3f] %s%s%s@%u.%s(",
 		time / 1000.0,
 		send ? " -> " : "",
+		intact ? "INTACT " : "",
 		target->interface->name, target->id,
 		closure->message->name);
 
diff --git a/src/scanner.c b/src/scanner.c
index 1f1e59a..515fe1c 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -1133,6 +1133,11 @@ emit_messages(struct wl_list *message_list,
 	wl_list_for_each(m, message_list, link) {
 		printf("\t{ \"%s\", \"", m->name);
 
+		/* make destructor flag the first letter in
+		 * signature */
+		if (m->destructor)
+			printf("D");
+
 		if (m->since > 1)
 			printf("%d", m->since);
 
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 0f1405c..30b0b66 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -598,7 +598,7 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
 	}
 
 	if (debug_client)
-		wl_closure_print(closure, &proxy->object, true);
+		wl_closure_print(closure, &proxy->object, true, false);
 
 	if (wl_closure_send(closure, proxy->display->connection)) {
 		wl_log("Error sending request: %m\n");
@@ -1157,13 +1157,13 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 
 	if (proxy->dispatcher) {
 		if (debug_client)
-			wl_closure_print(closure, &proxy->object, false);
+			wl_closure_print(closure, &proxy->object, false, false);
 
 		wl_closure_dispatch(closure, proxy->dispatcher,
 				    &proxy->object, opcode);
 	} else if (proxy->object.implementation) {
 		if (debug_client)
-			wl_closure_print(closure, &proxy->object, false);
+			wl_closure_print(closure, &proxy->object, false, false);
 
 		wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
 				  &proxy->object, opcode, proxy->user_data);
diff --git a/src/wayland-private.h b/src/wayland-private.h
index db76081..00e34e0 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -160,7 +160,8 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
 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);
+wl_closure_print(struct wl_closure *closure, struct wl_object *target,
+		 int send, int intact);
 void
 wl_closure_destroy(struct wl_closure *closure);
 
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 0558634..b777711 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -116,6 +116,7 @@ struct wl_resource {
 	void *data;
 	int version;
 	wl_dispatcher_func_t dispatcher;
+	int intact;
 };
 
 static int debug_server = 0;
@@ -139,7 +140,7 @@ wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
 		resource->client->error = 1;
 
 	if (debug_server)
-		wl_closure_print(closure, object, true);
+		wl_closure_print(closure, object, true, resource->intact);
 
 	wl_closure_destroy(closure);
 }
@@ -179,7 +180,7 @@ wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
 		resource->client->error = 1;
 
 	if (debug_server)
-		wl_closure_print(closure, object, true);
+		wl_closure_print(closure, object, true, resource->intact);
 
 	wl_closure_destroy(closure);
 }
@@ -228,6 +229,12 @@ wl_resource_post_error(struct wl_resource *resource,
 }
 
 static int
+wl_message_is_destructor(const struct wl_message *message)
+{
+	return message->signature[0] == 'D';
+}
+
+static int
 wl_client_connection_data(int fd, uint32_t mask, void *data)
 {
 	struct wl_client *client = data;
@@ -327,7 +334,17 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 		}
 
 		if (debug_server)
-			wl_closure_print(closure, object, false);
+			wl_closure_print(closure, object,
+					 false, resource->intact);
+
+		/* intact resources dispatch only destructors */
+		if (resource->intact &&
+		    !wl_message_is_destructor(message)) {
+			/* Let user know why the request "vanished" */
+			wl_log("Skipping non-destructor on intact resource\n");
+			wl_closure_destroy(closure);
+			continue;
+		}
 
 		if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
 		    resource->dispatcher == NULL) {
@@ -1276,6 +1293,18 @@ wl_resource_set_implementation(struct wl_resource *resource,
 }
 
 WL_EXPORT void
+wl_resource_set_intact(struct wl_resource *resource)
+{
+	resource->intact = 1;
+}
+
+WL_EXPORT int
+wl_resource_get_intact(struct wl_resource *resource)
+{
+	return resource->intact;
+}
+
+WL_EXPORT void
 wl_resource_set_dispatcher(struct wl_resource *resource,
 			   wl_dispatcher_func_t dispatcher,
 			   const void *implementation,
@@ -1298,20 +1327,18 @@ wl_resource_create(struct wl_client *client,
 	if (resource == NULL)
 		return NULL;
 
+	memset(resource, 0, sizeof *resource);
+
 	if (id == 0)
 		id = wl_map_insert_new(&client->objects, 0, NULL);
 
 	resource->object.id = id;
 	resource->object.interface = interface;
-	resource->object.implementation = NULL;
 
 	wl_signal_init(&resource->destroy_signal);
 
-	resource->destroy = NULL;
 	resource->client = client;
-	resource->data = NULL;
 	resource->version = version;
-	resource->dispatcher = NULL;
 
 	if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) {
 		wl_resource_post_error(client->display_resource,
diff --git a/src/wayland-server.h b/src/wayland-server.h
index af2f03d..8dad02c 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -353,6 +353,12 @@ struct wl_resource *
 wl_resource_create(struct wl_client *client,
 		   const struct wl_interface *interface,
 		   int version, uint32_t id);
+
+void
+wl_resource_set_intact(struct wl_resource *resource);
+int
+wl_resource_get_intact(struct wl_resource *resource);
+
 void
 wl_resource_set_implementation(struct wl_resource *resource,
 			       const void *implementation,
-- 
2.1.0



More information about the wayland-devel mailing list