[PATCH 3/7] Convert wl_closure to use wl_argument and enable dispatchers

Jason Ekstrand jason at jlekstrand.net
Fri Feb 1 08:09:44 PST 2013


Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/connection.c      | 343 +++++++++++++++++++++++++-------------------------
 src/wayland-client.c  |  29 +++--
 src/wayland-private.h |  14 ++-
 src/wayland-server.c  |  22 +---
 src/wayland-util.h    |  26 +++-
 5 files changed, 223 insertions(+), 211 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index 76aefb7..859446a 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -386,16 +386,8 @@ wl_message_size_extra(const struct wl_message *message)
 	for (i = 0, extra = 0; message->signature[i]; i++) {
 
 		switch (message->signature[i]) {
-		case 's':
-		case 'o':
-		case 'n':
-			extra += sizeof (void *);
-			break;
 		case 'a':
-			extra += sizeof (void *) + sizeof (struct wl_array);
-			break;
-		case 'h':
-			extra += sizeof (int);
+			extra += sizeof (struct wl_array);
 			break;
 		default:
 			break;
@@ -444,21 +436,70 @@ arg_count_for_signature(const char *signature)
 	return count;
 }
 
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+			 int count, va_list ap)
+{
+	int i;
+	const char *sig_iter;
+	struct argument_details arg;
+
+	sig_iter = signature;
+	for (i = 0; i < count; i++) {
+		sig_iter = get_next_argument(sig_iter, &arg);
+
+		switch(arg.type) {
+		case 'i':
+			args[i].i = va_arg(ap, int32_t);
+			break;
+		case 'u':
+			args[i].u = va_arg(ap, uint32_t);
+			break;
+		case 'f':
+			args[i].f = va_arg(ap, wl_fixed_t);
+			break;
+		case 's':
+			args[i].s = va_arg(ap, const char *);
+			break;
+		case 'o':
+			args[i].o = va_arg(ap, struct wl_object *);
+			break;
+		case 'n':
+			args[i].o = va_arg(ap, struct wl_object *);
+			break;
+		case 'a':
+			args[i].a = va_arg(ap, struct wl_array *);
+			break;
+		case 'h':
+			args[i].h = va_arg(ap, int32_t);
+			break;
+		case '\0':
+			return;
+		}
+	}
+}
+
 struct wl_closure *
-wl_closure_vmarshal(struct wl_object *sender,
-		    uint32_t opcode, va_list ap,
+wl_closure_marshal(struct wl_object *sender,
+		    uint32_t opcode, union wl_argument *args,
 		    const struct wl_message *message)
 {
 	struct wl_closure *closure;
-	struct wl_object **objectp, *object;
+	struct wl_object *object;
 	uint32_t length, aligned, *p, *start, size, *end;
 	int dup_fd;
-	struct wl_array **arrayp, *array;
-	const char **sp, *s;
-	const char *signature = message->signature;
+	struct wl_array *array;
+	const char *s, *signature;
 	struct argument_details arg;
 	char *extra;
-	int i, count, fd, extra_size, *fd_ptr;
+	int i, count, fd, extra_size;
+
+	count = arg_count_for_signature(message->signature);
+	if (count > WL_CLOSURE_MAX_ARGS) {
+		printf("too many args (%d)\n", count);
+		errno = EINVAL;
+		return NULL;
+	}
 
 	/* FIXME: Match old fixed allocation for now */
 	closure = malloc(sizeof *closure + 1024);
@@ -466,47 +507,36 @@ wl_closure_vmarshal(struct wl_object *sender,
 		return NULL;
 
 	extra_size = wl_message_size_extra(message);
-	count = arg_count_for_signature(signature) + 2;
 	extra = (char *) closure->buffer;
 	start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)];
 	end = &closure->buffer[256];
 	p = &start[2];
 
-	closure->types[0] = &ffi_type_pointer;
-	closure->types[1] = &ffi_type_pointer;
-
-	for (i = 2; i < count; i++) {
+	signature = message->signature;
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 
 		switch (arg.type) {
 		case 'f':
-			closure->types[i] = &ffi_type_sint32;
-			closure->args[i] = p;
+			closure->args[i].f = args[i].f;
 			if (end - p < 1)
 				goto err;
-			*p++ = va_arg(ap, wl_fixed_t);
+			*p++ = args[i].f;
 			break;
 		case 'u':
-			closure->types[i] = &ffi_type_uint32;
-			closure->args[i] = p;
+			closure->args[i].u = args[i].u;
 			if (end - p < 1)
 				goto err;
-			*p++ = va_arg(ap, uint32_t);
+			*p++ = args[i].u;
 			break;
 		case 'i':
-			closure->types[i] = &ffi_type_sint32;
-			closure->args[i] = p;
+			closure->args[i].i = args[i].i;
 			if (end - p < 1)
 				goto err;
-			*p++ = va_arg(ap, int32_t);
+			*p++ = args[i].i;
 			break;
 		case 's':
-			closure->types[i] = &ffi_type_pointer;
-			closure->args[i] = extra;
-			sp = (const char **) extra;
-			extra += sizeof *sp;
-
-			s = va_arg(ap, const char *);
+			s = args[i].s;
 
 			if (!arg.nullable && s == NULL)
 				goto err_null;
@@ -519,53 +549,42 @@ wl_closure_vmarshal(struct wl_object *sender,
 
 			if (length > 0) {
 				memcpy(p, s, length);
-				*sp = (const char *) p;
+				closure->args[i].s = (const char *) p;
 			} else
-				*sp = NULL;
+				closure->args[i].s = NULL;
 
 			memset((char *) p + length, 0, aligned - length);
 			p += aligned / sizeof *p;
 			break;
 		case 'o':
-			closure->types[i] = &ffi_type_pointer;
-			closure->args[i] = extra;
-			objectp = (struct wl_object **) extra;
-			extra += sizeof *objectp;
-
-			object = va_arg(ap, struct wl_object *);
-
+			object = args[i].o;
 			if (!arg.nullable && object == NULL)
 				goto err_null;
 
-			*objectp = object;
+			closure->args[i].o = object;
+
 			if (end - p < 1)
 				goto err;
 			*p++ = object ? object->id : 0;
 			break;
 
 		case 'n':
-			closure->types[i] = &ffi_type_uint32;
-			closure->args[i] = p;
-			object = va_arg(ap, struct wl_object *);
+			object = args[i].o;
 			if (end - p < 1)
 				goto err;
 
 			if (!arg.nullable && object == NULL)
 				goto err_null;
 
-			*p++ = object ? object->id : 0;
+			closure->args[i].n = object ? object->id : 0;
+			*p++ = closure->args[i].n;
 			break;
 
 		case 'a':
-			closure->types[i] = &ffi_type_pointer;
-			closure->args[i] = extra;
-			arrayp = (struct wl_array **) extra;
-			extra += sizeof *arrayp;
-
-			*arrayp = (struct wl_array *) extra;
-			extra += sizeof **arrayp;
+			closure->args[i].a = (struct wl_array *) extra;
+			extra += sizeof *closure->args[i].a;
 
-			array = va_arg(ap, struct wl_array *);
+			array = args[i].a;
 
 			if (!arg.nullable && array == NULL)
 				goto err_null;
@@ -581,26 +600,21 @@ wl_closure_vmarshal(struct wl_object *sender,
 			*p++ = array->size;
 			memcpy(p, array->data, array->size);
 
-			(*arrayp)->size = array->size;
-			(*arrayp)->alloc = array->alloc;
-			(*arrayp)->data = p;
+			closure->args[i].a->size = array->size;
+			closure->args[i].a->alloc = array->alloc;
+			closure->args[i].a->data = p;
 
 			p += DIV_ROUNDUP(array->size, sizeof *p);
 			break;
 
 		case 'h':
-			closure->types[i] = &ffi_type_sint;
-			closure->args[i] = extra;
-			fd_ptr = (int *) extra;
-			extra += sizeof *fd_ptr;
-
-			fd = va_arg(ap, int);
+			fd = args[i].h;
 			dup_fd = wl_os_dupfd_cloexec(fd, 0);
 			if (dup_fd < 0) {
 				fprintf(stderr, "dup failed: %m");
 				abort();
 			}
-			*fd_ptr = dup_fd;
+			closure->args[i].h = dup_fd;
 			break;
 		default:
 			fprintf(stderr, "unhandled format code: '%c'\n",
@@ -618,21 +632,18 @@ wl_closure_vmarshal(struct wl_object *sender,
 	closure->message = message;
 	closure->count = count;
 
-	ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI,
-		     closure->count, &ffi_type_void, closure->types);
-
 	return closure;
 
 err:
 	printf("request too big to marshal, maximum size is %zu\n",
 	       sizeof closure->buffer);
 	errno = ENOMEM;
-	free(closure);
+	wl_closure_destroy(closure);
 
 	return NULL;
 
 err_null:
-	free(closure);
+	wl_closure_destroy(closure);
 	wl_log("error marshalling arguments for %s:%i.%s (signature %s): "
 	       "null value passed for arg %i\n",
 	       sender->interface->name, sender->id, message->name,
@@ -642,22 +653,34 @@ err_null:
 }
 
 struct wl_closure *
+wl_closure_vmarshal(struct wl_object *sender,
+		    uint32_t opcode, va_list ap,
+		    const struct wl_message *message)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+
+	wl_argument_from_va_list(message->signature, args,
+				 WL_CLOSURE_MAX_ARGS, ap);
+
+	return wl_closure_marshal(sender, opcode, args, message);
+}
+
+struct wl_closure *
 wl_connection_demarshal(struct wl_connection *connection,
 			uint32_t size,
 			struct wl_map *objects,
 			const struct wl_message *message)
 {
-	uint32_t *p, *next, *end, length, **id;
-	int *fd;
-	char *extra, **s;
+	uint32_t *p, *next, *end, length, id;
+	int fd;
+	char *extra, *s;
 	unsigned int i, count, extra_space;
-	const char *signature = message->signature;
+	const char *signature;
 	struct argument_details arg;
-	struct wl_array **array;
 	struct wl_closure *closure;
 
-	count = arg_count_for_signature(signature) + 2;
-	if (count > ARRAY_LENGTH(closure->types)) {
+	count = arg_count_for_signature(message->signature);
+	if (count > WL_CLOSURE_MAX_ARGS) {
 		printf("too many args (%d)\n", count);
 		errno = EINVAL;
 		wl_connection_consume(connection, size);
@@ -670,15 +693,15 @@ wl_connection_demarshal(struct wl_connection *connection,
 		return NULL;
 
 	closure->message = message;
-	closure->types[0] = &ffi_type_pointer;
-	closure->types[1] = &ffi_type_pointer;
 	closure->start = closure->buffer;
 
 	wl_connection_copy(connection, closure->buffer, size);
 	p = &closure->buffer[2];
 	end = (uint32_t *) ((char *) p + size);
 	extra = (char *) end;
-	for (i = 2; i < count; i++) {
+
+	signature = message->signature;
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 
 		if (p + 1 > end) {
@@ -691,19 +714,15 @@ wl_connection_demarshal(struct wl_connection *connection,
 
 		switch (arg.type) {
 		case 'u':
-			closure->types[i] = &ffi_type_uint32;
-			closure->args[i] = p++;
+			closure->args[i].u = *p++;
 			break;
 		case 'i':
-			closure->types[i] = &ffi_type_sint32;
-			closure->args[i] = p++;
+			closure->args[i].i = *p++;
 			break;
 		case 'f':
-			closure->types[i] = &ffi_type_sint32;
-			closure->args[i] = p++;
+			closure->args[i].f = *p++;
 			break;
 		case 's':
-			closure->types[i] = &ffi_type_pointer;
 			length = *p++;
 
 			next = p + DIV_ROUNDUP(length, sizeof *p);
@@ -715,50 +734,40 @@ wl_connection_demarshal(struct wl_connection *connection,
 				goto err;
 			}
 
-			s = (char **) extra;
-			extra += sizeof *s;
-			closure->args[i] = s;
 
 			if (length == 0) {
-				*s = NULL;
+				s = NULL;
 			} else {
-				*s = (char *) p;
+				s = (char *) p;
 			}
 
-			if (length > 0 && (*s)[length - 1] != '\0') {
+			if (length > 0 && s[length - 1] != '\0') {
 				printf("string not nul-terminated, "
 				       "message %s(%s)\n",
 				       message->name, message->signature);
 				errno = EINVAL;
 				goto err;
 			}
+			closure->args[i].s = s;
 			p = next;
 			break;
 		case 'o':
-			closure->types[i] = &ffi_type_pointer;
-			id = (uint32_t **) extra;
-			extra += sizeof *id;
-			closure->args[i] = id;
-			*id = p;
+			id = *p++;
+			closure->args[i].n = id;
 
-			if (**id == 0 && !arg.nullable) {
+			if (id == 0 && !arg.nullable) {
 				printf("NULL object received on non-nullable "
 				       "type, message %s(%s)\n", message->name,
 				       message->signature);
 				errno = EINVAL;
 				goto err;
 			}
-
-			p++;
 			break;
 		case 'n':
-			closure->types[i] = &ffi_type_pointer;
-			id = (uint32_t **) extra;
-			extra += sizeof *id;
-			closure->args[i] = id;
-			*id = p;
+			id = *p++;
+			closure->args[i].n = id;
 
-			if (**id == 0 && !arg.nullable) {
+			if (id == 0 && !arg.nullable) {
 				printf("NULL new ID received on non-nullable "
 				       "type, message %s(%s)\n", message->name,
 				       message->signature);
@@ -766,18 +775,16 @@ wl_connection_demarshal(struct wl_connection *connection,
 				goto err;
 			}
 
-			if (wl_map_reserve_new(objects, *p) < 0) {
+			if (wl_map_reserve_new(objects, id) < 0) {
 				printf("not a valid new object id (%d), "
 				       "message %s(%s)\n",
-				       *p, message->name, message->signature);
+				       id, message->name, message->signature);
 				errno = EINVAL;
 				goto err;
 			}
 
-			p++;
 			break;
 		case 'a':
-			closure->types[i] = &ffi_type_pointer;
 			length = *p++;
 
 			next = p + DIV_ROUNDUP(length, sizeof *p);
@@ -789,27 +796,18 @@ wl_connection_demarshal(struct wl_connection *connection,
 				goto err;
 			}
 
-			array = (struct wl_array **) extra;
-			extra += sizeof *array;
-			closure->args[i] = array;
-
-			*array = (struct wl_array *) extra;
-			extra += sizeof **array;
+			closure->args[i].a = (struct wl_array *) extra;
+			extra += sizeof *closure->args[i].a;
 
-			(*array)->size = length;
-			(*array)->alloc = 0;
-			(*array)->data = p;
+			closure->args[i].a->size = length;
+			closure->args[i].a->alloc = 0;
+			closure->args[i].a->data = p;
 			p = next;
 			break;
 		case 'h':
-			closure->types[i] = &ffi_type_sint;
-
-			fd = (int *) extra;
-			extra += sizeof *fd;
-			closure->args[i] = fd;
-
-			wl_buffer_copy(&connection->fds_in, fd, sizeof *fd);
-			connection->fds_in.tail += sizeof *fd;
+			wl_buffer_copy(&connection->fds_in, &fd, sizeof fd);
+			connection->fds_in.tail += sizeof fd;
+			closure->args[i].h = fd;
 			break;
 		default:
 			printf("unknown type\n");
@@ -818,17 +816,13 @@ wl_connection_demarshal(struct wl_connection *connection,
 		}
 	}
 
-	closure->count = i;
-
-	ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI,
-		     closure->count, &ffi_type_void, closure->types);
+	closure->count = count;
 
 	wl_connection_consume(connection, size);
 
 	return closure;
 
  err:
-	closure->count = i;
 	wl_closure_destroy(closure);
 	wl_connection_consume(connection, size);
 
@@ -851,7 +845,7 @@ interface_equal(const struct wl_interface *a, const struct wl_interface *b)
 int
 wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
 {
-	struct wl_object **object;
+	struct wl_object *object;
 	const struct wl_message *message;
 	const char *signature;
 	struct argument_details arg;
@@ -860,36 +854,38 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
 
 	message = closure->message;
 	signature = message->signature;
-	count = arg_count_for_signature(signature) + 2;
-	for (i = 2; i < count; i++) {
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 		switch (arg.type) {
 		case 'o':
-			id = **(uint32_t **) closure->args[i];
-			object = closure->args[i];
-			*object = wl_map_lookup(objects, id);
-			if (*object == WL_ZOMBIE_OBJECT) {
+			id = closure->args[i].n;
+			closure->args[i].o = NULL;
+
+			object = wl_map_lookup(objects, id);
+			if (object == WL_ZOMBIE_OBJECT) {
 				/* references object we've already
 				 * destroyed client side */
-				*object = NULL;
-			} else if (*object == NULL && id != 0) {
+				object = NULL;
+			} else if (object == NULL && id != 0) {
 				printf("unknown object (%u), message %s(%s)\n",
 				       id, message->name, message->signature);
-				*object = NULL;
+				object = NULL;
 				errno = EINVAL;
 				return -1;
 			}
 
-			if (*object != NULL && message->types[i-2] != NULL &&
-			    !interface_equal((*object)->interface,
-					     message->types[i-2])) {
+			if (object != NULL && message->types[i] != NULL &&
+			    !interface_equal((object)->interface,
+					     message->types[i])) {
 				printf("invalid object (%u), type (%s), "
 				       "message %s(%s)\n",
-				       id, (*object)->interface->name,
+				       id, (object)->interface->name,
 				       message->name, message->signature);
 				errno = EINVAL;
 				return -1;
 			}
+			closure->args[i].o = object;
 		}
 	}
 
@@ -898,14 +894,23 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
 
 void
 wl_closure_invoke(struct wl_closure *closure,
-		  struct wl_object *target, void (*func)(void), void *data)
+		  struct wl_object *target, uint32_t opcode, void *data)
 {
-	int result;
+	wl_interface_dispatcher_func_t dispatcher;
 
-	closure->args[0] = &data;
-	closure->args[1] = ⌖
+	if ((target->interface->version >> 16) >= 1) {
+		/* The dispatcher field is new as of version 1 */
+		dispatcher = target->interface->dispatcher;
+	} else {
+		dispatcher = NULL;
+	}
+
+	if (dispatcher == NULL)
+		dispatcher = &wl_interface_default_dispatcher;
+
+	assert(dispatcher);
 
-	ffi_call(&closure->cif, func, &result, closure->args);
+	(*dispatcher)(target, opcode, closure->message, data, closure->args);
 }
 
 static int
@@ -916,16 +921,16 @@ copy_fds_to_connection(struct wl_closure *closure,
 	uint32_t i, count;
 	struct argument_details arg;
 	const char *signature = message->signature;
-	int *fd;
+	int fd;
 
-	count = arg_count_for_signature(signature) + 2;
-	for (i = 2; i < count; i++) {
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 		if (arg.type != 'h')
 			continue;
 
-		fd = closure->args[i];
-		if (wl_connection_put_fd(connection, *fd)) {
+		fd = closure->args[i].h;
+		if (wl_connection_put_fd(connection, fd)) {
 			fprintf(stderr, "request could not be marshaled: "
 				"can't send file descriptor");
 			return -1;
@@ -981,12 +986,12 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
 		target->interface->name, target->id,
 		closure->message->name);
 
-	for (i = 2; i < closure->count; i++) {
+	for (i = 0; i < closure->count; i++) {
 		signature = get_next_argument(signature, &arg);
-		if (i > 2)
+		if (i > 0)
 			fprintf(stderr, ", ");
 
-		value = closure->args[i];
+		value = &closure->args[i];
 		switch (arg.type) {
 		case 'u':
 			fprintf(stderr, "%u", value->uint32);
@@ -1012,13 +1017,11 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
 			break;
 		case 'n':
 			fprintf(stderr, "new id %s@",
-				(closure->message->types[i - 2]) ?
-				 closure->message->types[i - 2]->name :
+				(closure->message->types[i]) ?
+				 closure->message->types[i]->name :
 				  "[unknown]");
-			if (send && value->new_id != 0)
+			if (value->new_id != 0)
 				fprintf(stderr, "%u", value->new_id);
-			else if (!send && value->object != NULL)
-				fprintf(stderr, "%u", value->object->id);
 			else
 				fprintf(stderr, "nil");
 			break;
@@ -1102,6 +1105,7 @@ wl_interface_default_dispatcher(struct wl_object *target, uint32_t opcode,
 	ffi_cif cif;
 	ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2];
 	void * ffi_args[WL_CLOSURE_MAX_ARGS + 2];
+	void (* const * implementation)(void);
 
 	count = arg_count_for_signature(message->signature);
 
@@ -1116,6 +1120,7 @@ wl_interface_default_dispatcher(struct wl_object *target, uint32_t opcode,
 	ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
 		     count + 2, &ffi_type_void, ffi_types);
 	
-	ffi_call(&cif, target->implementation[opcode], NULL, ffi_args);
+	implementation = target->implementation;
+	ffi_call(&cif, implementation[opcode], NULL, ffi_args);
 }
 
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 785f4ee..a0efb83 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -669,21 +669,21 @@ create_proxies(struct wl_proxy *sender, struct wl_closure *closure)
 	int count;
 
 	signature = closure->message->signature;
-	count = arg_count_for_signature(signature) + 2;
-	for (i = 2; i < count; i++) {
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 		switch (arg.type) {
 		case 'n':
-			id = **(uint32_t **) closure->args[i];
+			id = closure->args[i].n;
 			if (id == 0) {
-				*(void **) closure->args[i] = NULL;
+				closure->args[i].o = NULL;
 				break;
 			}
 			proxy = wl_proxy_create_for_id(sender, id,
-						       closure->message->types[i - 2]);
+						       closure->message->types[i]);
 			if (proxy == NULL)
 				return -1;
-			*(void **) closure->args[i] = proxy;
+			closure->args[i].o = (struct wl_object *)proxy;
 			break;
 		default:
 			break;
@@ -702,13 +702,13 @@ increase_closure_args_refcount(struct wl_closure *closure)
 	struct wl_proxy *proxy;
 
 	signature = closure->message->signature;
-	count = arg_count_for_signature(signature) + 2;
-	for (i = 2; i < count; i++) {
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 		switch (arg.type) {
 		case 'n':
 		case 'o':
-			proxy = *(struct wl_proxy **) closure->args[i];
+			proxy = (struct wl_proxy *) closure->args[i].o;
 			if (proxy)
 				proxy->refcount++;
 			break;
@@ -779,16 +779,16 @@ decrease_closure_args_refcount(struct wl_closure *closure)
 	struct wl_proxy *proxy;
 
 	signature = closure->message->signature;
-	count = arg_count_for_signature(signature) + 2;
-	for (i = 2; i < count; i++) {
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
 		signature = get_next_argument(signature, &arg);
 		switch (arg.type) {
 		case 'n':
 		case 'o':
-			proxy = *(struct wl_proxy **) closure->args[i];
+			proxy = (struct wl_proxy *) closure->args[i].o;
 			if (proxy) {
 				if (proxy->flags & WL_PROXY_FLAG_DESTROYED)
-					*(void **) closure->args[i] = NULL;
+					closure->args[i].o = NULL;
 
 				proxy->refcount--;
 				if (!proxy->refcount)
@@ -836,8 +836,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 		if (wl_debug)
 			wl_closure_print(closure, &proxy->object, false);
 
-		wl_closure_invoke(closure, &proxy->object,
-				  proxy->object.implementation[opcode],
+		wl_closure_invoke(closure, &proxy->object, opcode,
 				  proxy->user_data);
 	}
 
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 18f280e..30bd19f 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -77,9 +77,7 @@ int wl_connection_queue(struct wl_connection *connection,
 struct wl_closure {
 	int count;
 	const struct wl_message *message;
-	ffi_type *types[WL_CLOSURE_MAX_ARGS];
-	ffi_cif cif;
-	void *args[WL_CLOSURE_MAX_ARGS];
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
 	uint32_t *start;
 	struct wl_list link;
 	struct wl_proxy *proxy;
@@ -97,6 +95,14 @@ get_next_argument(const char *signature, struct argument_details *details);
 int
 arg_count_for_signature(const char *signature);
 
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+			 int count, va_list ap);
+
+struct wl_closure *
+wl_closure_marshal(struct wl_object *sender,
+		    uint32_t opcode, union wl_argument *args,
+		    const struct wl_message *message);
 struct wl_closure *
 wl_closure_vmarshal(struct wl_object *sender,
 		    uint32_t opcode, va_list ap,
@@ -113,7 +119,7 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);
 
 void
 wl_closure_invoke(struct wl_closure *closure,
-		  struct wl_object *target, void (*func)(void), void *data);
+		  struct wl_object *target, uint32_t opcode, void *data);
 int
 wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
 int
diff --git a/src/wayland-server.c b/src/wayland-server.c
index dae7177..e45b880 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -191,23 +191,6 @@ wl_resource_post_error(struct wl_resource *resource,
 			       WL_DISPLAY_ERROR, resource, code, buffer);
 }
 
-static void
-deref_new_objects(struct wl_closure *closure)
-{
-	const char *signature;
-	int i;
-
-	signature = closure->message->signature;
-	for (i = 0; signature[i]; i++) {
-		switch (signature[i]) {
-		case 'n':
-			closure->args[i + 2] = *(uint32_t **) closure->args[i + 2];
-			closure->types[i] = &ffi_type_uint32;
-			break;
-		}
-	}
-}
-
 static int
 wl_client_connection_data(int fd, uint32_t mask, void *data)
 {
@@ -294,10 +277,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 		if (wl_debug)
 			wl_closure_print(closure, object, false);
 
-		deref_new_objects(closure);
-
-		wl_closure_invoke(closure, object,
-				  object->implementation[opcode], client);
+		wl_closure_invoke(closure, object, opcode, client);
 
 		wl_closure_destroy(closure);
 
diff --git a/src/wayland-util.h b/src/wayland-util.h
index df7b384..bca25ed 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -46,18 +46,40 @@ struct wl_message {
 	const struct wl_interface **types;
 };
 
+union wl_argument;
+struct wl_object;
+
+typedef void (*wl_interface_dispatcher_func_t)(struct wl_object *, uint32_t,
+					       const struct wl_message *,
+					       void *, union wl_argument *);
+/**
+ * wl_interface - object method interface
+ *
+ * This structure has been extended since libwayland version 1.  The version
+ * field now represents both an interface version and a structure version.
+ * The upper 16 bits represent the version of the structure with the original
+ * version being version 0.  The lower 16 bits represent the interface version
+ * as specified in the interface XML file.
+ *
+ * This way, as long as the version number is something sane and instances of
+ * "struct wl_interface" are never statically allocated, older software should
+ * still complie and link against newer versions of libwayland.
+ */
 struct wl_interface {
 	const char *name;
-	int version;
+	uint32_t version;
 	int method_count;
 	const struct wl_message *methods;
 	int event_count;
 	const struct wl_message *events;
+
+	/* Added in version 1 */
+	wl_interface_dispatcher_func_t dispatcher;
 };
 
 struct wl_object {
 	const struct wl_interface *interface;
-	void (* const * implementation)(void);
+	const void *implementation;
 	uint32_t id;
 };
 
-- 
1.8.1



More information about the wayland-devel mailing list