diff options
author | Kristian Høgsberg <krh@bitplanet.net> | 2010-08-30 09:47:36 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2010-08-30 09:47:36 -0400 |
commit | 45b7789a8b59d86d35ff29acb1b1d48a8e666f6e (patch) | |
tree | 09dacc23a5718446a175f9f1e263484c2b4a7cd5 | |
parent | 8ca1cc20a1db53f670ed5d53b0b74287c0c8d8ba (diff) |
Return a closure object from wl_connection_demarshal
This way we can invoke it multiple times without having to demarshal
and build the cfi every time.
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | connection.c | 169 | ||||
-rw-r--r-- | connection.h | 17 | ||||
-rw-r--r-- | wayland-client.c | 28 | ||||
-rw-r--r-- | wayland-server.c | 30 |
5 files changed, 143 insertions, 105 deletions
@@ -1,5 +1,9 @@ Core wayland protocol + - The message format has to include information about number of fds + in the message so we can skip a message correctly. Or we should + just give up on trying to recover from unknown messages. + - generate pointer_focus (and drag focus) on raise/lower, move windows, all kinds of changes in surface stacking. diff --git a/connection.c b/connection.c index cd9a45d..8d4f19f 100644 --- a/connection.c +++ b/connection.c @@ -45,6 +45,21 @@ struct wl_buffer { #define MASK(i) ((i) & 4095) +struct wl_closure { + int count; + const struct wl_message *message; + ffi_type *types[20]; + ffi_cif cif; + union { + uint32_t uint32; + char *string; + void *object; + uint32_t new_id; + struct wl_array *array; + } values[20]; + void *args[20]; +}; + struct wl_connection { struct wl_buffer in, out; struct wl_buffer fds_in, fds_out; @@ -52,6 +67,7 @@ struct wl_connection { int fd; void *data; wl_connection_update_func_t update; + struct wl_closure closure; }; static void @@ -380,31 +396,20 @@ wl_connection_vmarshal(struct wl_connection *connection, wl_connection_write(connection, args, size); } -int +struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_hash_table *objects, - void (*func)(void), - void *data, struct wl_object *target, const struct wl_message *message) { - ffi_type *types[20]; - ffi_cif cif; - uint32_t *p, *next, *end, result, length; - int i, count, fds_tail, ret = 0; - union { - uint32_t uint32; - char *string; - void *object; - uint32_t new_id; - struct wl_array *array; - } values[20]; - void *args[20]; + uint32_t *p, *next, *end, length; + int i, count; struct wl_object *object; uint32_t buffer[64]; + struct wl_closure *closure = &connection->closure; count = strlen(message->signature) + 2; - if (count > ARRAY_LENGTH(types)) { + if (count > ARRAY_LENGTH(closure->types)) { printf("too many args (%d)\n", count); assert(0); } @@ -414,36 +419,33 @@ wl_connection_demarshal(struct wl_connection *connection, assert(0); } - types[0] = &ffi_type_pointer; - values[0].object = data; - args[0] = &values[0]; + closure->message = message; + closure->types[0] = &ffi_type_pointer; + closure->args[0] = &closure->values[0]; - types[1] = &ffi_type_pointer; - values[1].object = target; - args[1] = &values[1]; + closure->types[1] = &ffi_type_pointer; + closure->args[1] = &closure->values[1]; wl_connection_copy(connection, buffer, size); p = &buffer[2]; end = (uint32_t *) ((char *) (p + size)); - fds_tail = connection->fds_in.tail; for (i = 2; i < count; i++) { if (p + 1 > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; - ret = -1; - goto out; + goto err; } switch (message->signature[i - 2]) { case 'u': case 'i': - types[i] = &ffi_type_uint32; - values[i].uint32 = *p++; + closure->types[i] = &ffi_type_uint32; + closure->values[i].uint32 = *p++; break; case 's': - types[i] = &ffi_type_pointer; + closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); @@ -452,53 +454,49 @@ wl_connection_demarshal(struct wl_connection *connection, "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; - ret = -1; - goto out; + goto err; } if (length == 0) { - values[i].string = NULL; + closure->values[i].string = NULL; } else { - values[i].string = malloc(length + 1); - if (values[i].string == NULL) { + closure->values[i].string = malloc(length + 1); + if (closure->values[i].string == NULL) { errno = ENOMEM; - ret = -1; - goto out; + goto err; } - memcpy(values[i].string, p, length); - values[i].string[length] = '\0'; + memcpy(closure->values[i].string, p, length); + closure->values[i].string[length] = '\0'; } p = next; break; case 'o': - types[i] = &ffi_type_pointer; + closure->types[i] = &ffi_type_pointer; object = wl_hash_table_lookup(objects, *p); if (object == NULL && *p != 0) { printf("unknown object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; - ret = -1; - goto out; + goto err; } - values[i].object = object; + closure->values[i].object = object; p++; break; case 'n': - types[i] = &ffi_type_uint32; - values[i].new_id = *p; + closure->types[i] = &ffi_type_uint32; + closure->values[i].new_id = *p; object = wl_hash_table_lookup(objects, *p); if (object != NULL) { printf("not a new object (%d), " "message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; - ret = -1; - goto out; + goto err; } p++; break; case 'a': - types[i] = &ffi_type_pointer; + closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); @@ -507,58 +505,77 @@ wl_connection_demarshal(struct wl_connection *connection, "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; - ret = -1; - goto out; + goto err; } - values[i].array = - malloc(length + sizeof *values[i].array); - if (values[i].array == NULL) { + closure->values[i].array = + malloc(length + sizeof *closure->values[i].array); + if (closure->values[i].array == NULL) { errno = ENOMEM; - ret = -1; - goto out; + goto err; } - values[i].array->size = length; - values[i].array->alloc = 0; - values[i].array->data = values[i].array + 1; - memcpy(values[i].array->data, p, length); + closure->values[i].array->size = length; + closure->values[i].array->alloc = 0; + closure->values[i].array->data = closure->values[i].array + 1; + memcpy(closure->values[i].array->data, p, length); p = next; break; case 'h': - types[i] = &ffi_type_uint32; + closure->types[i] = &ffi_type_uint32; wl_buffer_copy(&connection->fds_in, - &values[i].uint32, - sizeof values[i].uint32); - connection->fds_in.tail += sizeof values[i].uint32; + &closure->values[i].uint32, + sizeof closure->values[i].uint32); + connection->fds_in.tail += + sizeof closure->values[i].uint32; break; default: printf("unknown type\n"); assert(0); break; } - args[i] = &values[i]; + closure->args[i] = &closure->values[i]; } - ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types); - ffi_call(&cif, func, &result, args); + closure->count = i; + ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI, + closure->count, &ffi_type_uint32, closure->types); - /* Slight hack here. We store the tail of fds_in here and - * consume will set fds_in.tail to that value */ - connection->fds_in_tail = connection->fds_in.tail; - connection->fds_in.tail = fds_tail; + wl_connection_consume(connection, size); - out: - count = i; - for (i = 2; i < count; i++) { - switch (message->signature[i - 2]) { + return closure; + + err: + closure->count = i; + wl_closure_destroy(closure); + + return NULL; +} + +void +wl_closure_invoke(struct wl_closure *closure, + struct wl_object *target, void (*func)(void), void *data) +{ + int result; + + closure->values[0].object = data; + closure->values[1].object = target; + + ffi_call(&closure->cif, func, &result, closure->args); +} + +void +wl_closure_destroy(struct wl_closure *closure) +{ + int i; + + for (i = 2; i < closure->count; i++) { + switch (closure->message->signature[i - 2]) { case 's': - free(values[i].string); + free(closure->values[i].string); break; case 'a': - free(values[i].array); + free(closure->values[i].array); break; } } - - return ret; } diff --git a/connection.h b/connection.h index 7f65e87..5f28888 100644 --- a/connection.h +++ b/connection.h @@ -27,6 +27,7 @@ #include "wayland-util.h" struct wl_connection; +struct wl_closure; #define WL_CONNECTION_READABLE 0x01 #define WL_CONNECTION_WRITABLE 0x02 @@ -48,11 +49,15 @@ void wl_connection_vmarshal(struct wl_connection *connection, uint32_t opcode, va_list ap, const struct wl_message *message); -int wl_connection_demarshal(struct wl_connection *connection, - uint32_t size, - struct wl_hash_table *objects, - void (*func)(void), - void *data, struct wl_object *target, - const struct wl_message *message); +struct wl_closure * +wl_connection_demarshal(struct wl_connection *connection, + uint32_t size, + struct wl_hash_table *objects, + const struct wl_message *message); +void +wl_closure_invoke(struct wl_closure *closure, + struct wl_object *target, void (*func)(void), void *data); +void +wl_closure_destroy(struct wl_closure *closure); #endif diff --git a/wayland-client.c b/wayland-client.c index c79cc65..3dc5544 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -340,6 +340,8 @@ handle_event(struct wl_display *display, uint32_t p[32]; struct wl_listener *listener; struct wl_proxy *proxy; + struct wl_closure *closure; + struct wl_message *message; wl_connection_copy(display->connection, p, size); if (id == 1) @@ -347,17 +349,21 @@ handle_event(struct wl_display *display, else proxy = wl_hash_table_lookup(display->objects, id); - if (proxy != NULL) - wl_list_for_each(listener, &proxy->listener_list, link) - wl_connection_demarshal(display->connection, - size, - display->objects, - listener->implementation[opcode], - listener->data, - &proxy->base, - &proxy->base.interface->events[opcode]); - - wl_connection_consume(display->connection, size); + if (proxy == NULL) { + wl_connection_consume(display->connection, size); + return; + } + + message = &proxy->base.interface->events[opcode]; + closure = wl_connection_demarshal(display->connection, + size, display->objects, message); + + wl_list_for_each(listener, &proxy->listener_list, link) + wl_closure_invoke(closure, &proxy->base, + listener->implementation[opcode], + listener->data); + + wl_closure_destroy(closure); } WL_EXPORT void diff --git a/wayland-server.c b/wayland-server.c index 196e67f..869bdd9 100644 --- a/wayland-server.c +++ b/wayland-server.c @@ -86,9 +86,11 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) struct wl_client *client = data; struct wl_connection *connection = client->connection; struct wl_object *object; + struct wl_closure *closure; + const struct wl_message *message; uint32_t p[2], opcode, size; uint32_t cmask = 0; - int len, ret; + int len; if (mask & WL_EVENT_READABLE) cmask |= WL_CONNECTION_READABLE; @@ -125,24 +127,28 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) continue; } - ret = wl_connection_demarshal(client->connection, - size, - client->display->objects, - object->implementation[opcode], - client, - object, - &object->interface->methods[opcode]); + message = &object->interface->methods[opcode]; + closure = wl_connection_demarshal(client->connection, size, + client->display->objects, + message); + len -= size; - if (ret < 0 && errno == EINVAL) + if (closure == NULL && errno == EINVAL) { wl_client_post_event(client, &client->display->base, WL_DISPLAY_INVALID_METHOD, p[0], opcode); - if (ret < 0 && errno == ENOMEM) + continue; + } else if (closure == NULL && errno == ENOMEM) { wl_client_post_event(client, &client->display->base, WL_DISPLAY_NO_MEMORY); + continue; + } + + wl_closure_invoke(closure, object, + object->implementation[opcode], client); + + wl_closure_destroy(closure); - wl_connection_consume(connection, size); - len -= size; } } |