From da9d6e6b563263a0438aa81e3c9a46106aec212f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= <krh@bitplanet.net>
Date: Thu, 14 Nov 2013 21:29:06 -0800
Subject: [PATCH] proxy race fix

---
 src/scanner.c        |  43 ++++++++-------
 src/wayland-client.c | 151 ++++++++++++++++++++++++++++++++++++++-------------
 src/wayland-client.h |   4 ++
 3 files changed, 140 insertions(+), 58 deletions(-)

diff --git a/src/scanner.c b/src/scanner.c
index 0fbaabd..fdda91e 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -654,31 +654,34 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
 		       "{\n");
 		if (ret) {
 			printf("\tstruct wl_proxy *%s;\n\n"
-			       "\t%s = wl_proxy_create("
-			       "(struct wl_proxy *) %s,\n",
-			       ret->name, ret->name, interface->name);
+			       "\t%s = wl_proxy_marshal_constructor("
+			       "(struct wl_proxy *) %s,\n"
+			       "\t\t\t %s_%s, ",
+			       ret->name, ret->name,
+			       interface->name,
+			       interface->uppercase_name,
+			       m->uppercase_name);
+
 			if (ret->interface_name == NULL)
-				printf("\t\t\t     interface);\n");
+				printf("interface");
 			else
-				printf("\t\t\t     &%s_interface);\n",
-				       ret->interface_name);
-
-			printf("\tif (!%s)\n"
-			       "\t\treturn NULL;\n\n",
-			       ret->name);
+				printf("&%s_interface", ret->interface_name);
+		} else {
+			printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
+			       "\t\t\t %s_%s",
+			       interface->name,
+			       interface->uppercase_name,
+			       m->uppercase_name);
 		}
 
-		printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
-		       "\t\t\t %s_%s",
-		       interface->name,
-		       interface->uppercase_name,
-		       m->uppercase_name);
-
 		wl_list_for_each(a, &m->arg_list, link) {
-			if (a->type == NEW_ID && a->interface_name == NULL)
-				printf(", interface->name, version");
-			printf(", ");
-			printf("%s", a->name);
+			if (a->type == NEW_ID) {
+				if (a->interface_name == NULL)
+					printf(", interface->name, version");
+				printf(", NULL");
+			} else {
+				printf(", %s", a->name);
+			}
 		}
 		printf(");\n");
 
diff --git a/src/wayland-client.c b/src/wayland-client.c
index e92317a..c26fc5b 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -194,6 +194,29 @@ wl_display_create_queue(struct wl_display *display)
 	return queue;
 }
 
+static struct wl_proxy *
+proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
+{
+	struct wl_proxy *proxy;
+	struct wl_display *display = factory->display;
+
+	proxy = malloc(sizeof *proxy);
+	if (proxy == NULL)
+		return NULL;
+
+	proxy->object.interface = interface;
+	proxy->object.implementation = NULL;
+	proxy->dispatcher = NULL;
+	proxy->display = display;
+	proxy->queue = factory->queue;
+	proxy->flags = 0;
+	proxy->refcount = 1;
+
+	proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
+
+	return proxy;
+}
+
 /** Create a proxy object with a given interface
  *
  * \param factory Factory proxy object
@@ -216,23 +239,11 @@ wl_display_create_queue(struct wl_display *display)
 WL_EXPORT struct wl_proxy *
 wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
 {
-	struct wl_proxy *proxy;
 	struct wl_display *display = factory->display;
-
-	proxy = malloc(sizeof *proxy);
-	if (proxy == NULL)
-		return NULL;
-
-	proxy->object.interface = interface;
-	proxy->object.implementation = NULL;
-	proxy->dispatcher = NULL;
-	proxy->display = display;
-	proxy->queue = factory->queue;
-	proxy->flags = 0;
-	proxy->refcount = 1;
+	struct wl_proxy *proxy;
 
 	pthread_mutex_lock(&display->mutex);
-	proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
+	proxy = proxy_create(factory, interface);
 	pthread_mutex_unlock(&display->mutex);
 
 	return proxy;
@@ -382,6 +393,77 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy,
 	return 0;
 }
 
+static struct wl_proxy *
+create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,
+		      union wl_argument *args,
+		      const struct wl_interface *interface)
+{
+	int i, count;
+	const char *signature;
+	struct argument_details arg;
+	struct wl_proxy *new_proxy = NULL;
+
+	signature = message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+
+		switch (arg.type) {
+		case 'n':
+			new_proxy = proxy_create(proxy, interface);
+			if (new_proxy == NULL)
+				return NULL;
+
+			args[i].o = &new_proxy->object;
+			break;
+		}
+	}
+
+	return new_proxy;
+}
+
+static struct wl_proxy *
+proxy_marshal_array(struct wl_proxy *proxy,
+		    uint32_t opcode, union wl_argument *args,
+		    const struct wl_interface *interface)
+{
+	struct wl_closure *closure;
+	struct wl_proxy *new_proxy = NULL;
+	const struct wl_message *message;
+
+	pthread_mutex_lock(&proxy->display->mutex);
+
+	message = &proxy->object.interface->methods[opcode];
+	if (interface) {
+		new_proxy = create_outgoing_proxy(proxy, message,
+						  args, interface);
+		if (new_proxy == NULL)
+			goto err_unlock;
+	}
+			
+	closure = wl_closure_marshal(&proxy->object, opcode, args, message);
+	if (closure == NULL) {
+		fprintf(stderr, "Error marshalling request\n");
+		abort();
+	}
+
+	if (wl_debug)
+		wl_closure_print(closure, &proxy->object, true);
+
+	if (wl_closure_send(closure, proxy->display->connection)) {
+		fprintf(stderr, "Error sending request: %m\n");
+		abort();
+	}
+
+	wl_closure_destroy(closure);
+
+ err_unlock:
+	pthread_mutex_unlock(&proxy->display->mutex);
+
+	return new_proxy;
+}
+
+
 /** Prepare a request to be sent to the compositor
  *
  * \param proxy The proxy object
@@ -421,7 +503,22 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
 				 args, WL_CLOSURE_MAX_ARGS, ap);
 	va_end(ap);
 
-	wl_proxy_marshal_array(proxy, opcode, args);
+	proxy_marshal_array(proxy, opcode, args, NULL);
+}
+
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode,
+			     const struct wl_interface *interface, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	va_list ap;
+
+	va_start(ap, interface);
+	wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	return proxy_marshal_array(proxy, opcode, args, interface);
 }
 
 /** Prepare a request to be sent to the compositor
@@ -445,29 +542,7 @@ WL_EXPORT void
 wl_proxy_marshal_array(struct wl_proxy *proxy, uint32_t opcode,
 		       union wl_argument *args)
 {
-	struct wl_closure *closure;
-
-	pthread_mutex_lock(&proxy->display->mutex);
-
-	closure = wl_closure_marshal(&proxy->object, opcode, args,
-				     &proxy->object.interface->methods[opcode]);
-
-	if (closure == NULL) {
-		fprintf(stderr, "Error marshalling request\n");
-		abort();
-	}
-
-	if (wl_debug)
-		wl_closure_print(closure, &proxy->object, true);
-
-	if (wl_closure_send(closure, proxy->display->connection)) {
-		fprintf(stderr, "Error sending request: %m\n");
-		abort();
-	}
-
-	wl_closure_destroy(closure);
-
-	pthread_mutex_unlock(&proxy->display->mutex);
+	proxy_marshal_array(proxy, opcode, args, NULL);
 }
 
 static void
diff --git a/src/wayland-client.h b/src/wayland-client.h
index 43ba3fc..4b19aef 100644
--- a/src/wayland-client.h
+++ b/src/wayland-client.h
@@ -126,6 +126,10 @@ void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode,
 			    union wl_argument *args);
 struct wl_proxy *wl_proxy_create(struct wl_proxy *factory,
 				 const struct wl_interface *interface);
+struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy,
+					      uint32_t opcode,
+					      const struct wl_interface *interface,
+					      ...);
 
 void wl_proxy_destroy(struct wl_proxy *proxy);
 int wl_proxy_add_listener(struct wl_proxy *proxy,
-- 
1.8.3.1

