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.
dev
Kristian Høgsberg 14 years ago
parent 8ca1cc20a1
commit 45b7789a8b
  1. 4
      TODO
  2. 169
      connection.c
  3. 17
      connection.h
  4. 28
      wayland-client.c
  5. 30
      wayland-server.c

@ -1,5 +1,9 @@
Core wayland protocol 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 - generate pointer_focus (and drag focus) on raise/lower, move
windows, all kinds of changes in surface stacking. windows, all kinds of changes in surface stacking.

@ -45,6 +45,21 @@ struct wl_buffer {
#define MASK(i) ((i) & 4095) #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_connection {
struct wl_buffer in, out; struct wl_buffer in, out;
struct wl_buffer fds_in, fds_out; struct wl_buffer fds_in, fds_out;
@ -52,6 +67,7 @@ struct wl_connection {
int fd; int fd;
void *data; void *data;
wl_connection_update_func_t update; wl_connection_update_func_t update;
struct wl_closure closure;
}; };
static void static void
@ -380,31 +396,20 @@ wl_connection_vmarshal(struct wl_connection *connection,
wl_connection_write(connection, args, size); wl_connection_write(connection, args, size);
} }
int struct wl_closure *
wl_connection_demarshal(struct wl_connection *connection, wl_connection_demarshal(struct wl_connection *connection,
uint32_t size, uint32_t size,
struct wl_hash_table *objects, struct wl_hash_table *objects,
void (*func)(void),
void *data, struct wl_object *target,
const struct wl_message *message) const struct wl_message *message)
{ {
ffi_type *types[20]; uint32_t *p, *next, *end, length;
ffi_cif cif; int i, count;
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];
struct wl_object *object; struct wl_object *object;
uint32_t buffer[64]; uint32_t buffer[64];
struct wl_closure *closure = &connection->closure;
count = strlen(message->signature) + 2; count = strlen(message->signature) + 2;
if (count > ARRAY_LENGTH(types)) { if (count > ARRAY_LENGTH(closure->types)) {
printf("too many args (%d)\n", count); printf("too many args (%d)\n", count);
assert(0); assert(0);
} }
@ -414,36 +419,33 @@ wl_connection_demarshal(struct wl_connection *connection,
assert(0); assert(0);
} }
types[0] = &ffi_type_pointer; closure->message = message;
values[0].object = data; closure->types[0] = &ffi_type_pointer;
args[0] = &values[0]; closure->args[0] = &closure->values[0];
types[1] = &ffi_type_pointer; closure->types[1] = &ffi_type_pointer;
values[1].object = target; closure->args[1] = &closure->values[1];
args[1] = &values[1];
wl_connection_copy(connection, buffer, size); wl_connection_copy(connection, buffer, size);
p = &buffer[2]; p = &buffer[2];
end = (uint32_t *) ((char *) (p + size)); end = (uint32_t *) ((char *) (p + size));
fds_tail = connection->fds_in.tail;
for (i = 2; i < count; i++) { for (i = 2; i < count; i++) {
if (p + 1 > end) { if (p + 1 > end) {
printf("message too short, " printf("message too short, "
"object (%d), message %s(%s)\n", "object (%d), message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
errno = EINVAL; errno = EINVAL;
ret = -1; goto err;
goto out;
} }
switch (message->signature[i - 2]) { switch (message->signature[i - 2]) {
case 'u': case 'u':
case 'i': case 'i':
types[i] = &ffi_type_uint32; closure->types[i] = &ffi_type_uint32;
values[i].uint32 = *p++; closure->values[i].uint32 = *p++;
break; break;
case 's': case 's':
types[i] = &ffi_type_pointer; closure->types[i] = &ffi_type_pointer;
length = *p++; length = *p++;
next = p + DIV_ROUNDUP(length, sizeof *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", "object (%d), message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
errno = EINVAL; errno = EINVAL;
ret = -1; goto err;
goto out;
} }
if (length == 0) { if (length == 0) {
values[i].string = NULL; closure->values[i].string = NULL;
} else { } else {
values[i].string = malloc(length + 1); closure->values[i].string = malloc(length + 1);
if (values[i].string == NULL) { if (closure->values[i].string == NULL) {
errno = ENOMEM; errno = ENOMEM;
ret = -1; goto err;
goto out;
} }
memcpy(values[i].string, p, length); memcpy(closure->values[i].string, p, length);
values[i].string[length] = '\0'; closure->values[i].string[length] = '\0';
} }
p = next; p = next;
break; break;
case 'o': case 'o':
types[i] = &ffi_type_pointer; closure->types[i] = &ffi_type_pointer;
object = wl_hash_table_lookup(objects, *p); object = wl_hash_table_lookup(objects, *p);
if (object == NULL && *p != 0) { if (object == NULL && *p != 0) {
printf("unknown object (%d), message %s(%s)\n", printf("unknown object (%d), message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
errno = EINVAL; errno = EINVAL;
ret = -1; goto err;
goto out;
} }
values[i].object = object; closure->values[i].object = object;
p++; p++;
break; break;
case 'n': case 'n':
types[i] = &ffi_type_uint32; closure->types[i] = &ffi_type_uint32;
values[i].new_id = *p; closure->values[i].new_id = *p;
object = wl_hash_table_lookup(objects, *p); object = wl_hash_table_lookup(objects, *p);
if (object != NULL) { if (object != NULL) {
printf("not a new object (%d), " printf("not a new object (%d), "
"message %s(%s)\n", "message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
errno = EINVAL; errno = EINVAL;
ret = -1; goto err;
goto out;
} }
p++; p++;
break; break;
case 'a': case 'a':
types[i] = &ffi_type_pointer; closure->types[i] = &ffi_type_pointer;
length = *p++; length = *p++;
next = p + DIV_ROUNDUP(length, sizeof *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", "object (%d), message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
errno = EINVAL; errno = EINVAL;
ret = -1; goto err;
goto out;
} }
values[i].array = closure->values[i].array =
malloc(length + sizeof *values[i].array); malloc(length + sizeof *closure->values[i].array);
if (values[i].array == NULL) { if (closure->values[i].array == NULL) {
errno = ENOMEM; errno = ENOMEM;
ret = -1; goto err;
goto out;
} }
values[i].array->size = length; closure->values[i].array->size = length;
values[i].array->alloc = 0; closure->values[i].array->alloc = 0;
values[i].array->data = values[i].array + 1; closure->values[i].array->data = closure->values[i].array + 1;
memcpy(values[i].array->data, p, length); memcpy(closure->values[i].array->data, p, length);
p = next; p = next;
break; break;
case 'h': case 'h':
types[i] = &ffi_type_uint32; closure->types[i] = &ffi_type_uint32;
wl_buffer_copy(&connection->fds_in, wl_buffer_copy(&connection->fds_in,
&values[i].uint32, &closure->values[i].uint32,
sizeof values[i].uint32); sizeof closure->values[i].uint32);
connection->fds_in.tail += sizeof values[i].uint32; connection->fds_in.tail +=
sizeof closure->values[i].uint32;
break; break;
default: default:
printf("unknown type\n"); printf("unknown type\n");
assert(0); assert(0);
break; break;
} }
args[i] = &values[i]; closure->args[i] = &closure->values[i];
} }
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types); closure->count = i;
ffi_call(&cif, func, &result, args); 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 wl_connection_consume(connection, size);
* consume will set fds_in.tail to that value */
connection->fds_in_tail = connection->fds_in.tail;
connection->fds_in.tail = fds_tail;
out: return closure;
count = i;
for (i = 2; i < count; i++) { err:
switch (message->signature[i - 2]) { 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': case 's':
free(values[i].string); free(closure->values[i].string);
break; break;
case 'a': case 'a':
free(values[i].array); free(closure->values[i].array);
break; break;
} }
} }
return ret;
} }

@ -27,6 +27,7 @@
#include "wayland-util.h" #include "wayland-util.h"
struct wl_connection; struct wl_connection;
struct wl_closure;
#define WL_CONNECTION_READABLE 0x01 #define WL_CONNECTION_READABLE 0x01
#define WL_CONNECTION_WRITABLE 0x02 #define WL_CONNECTION_WRITABLE 0x02
@ -48,11 +49,15 @@ void wl_connection_vmarshal(struct wl_connection *connection,
uint32_t opcode, va_list ap, uint32_t opcode, va_list ap,
const struct wl_message *message); const struct wl_message *message);
int wl_connection_demarshal(struct wl_connection *connection, struct wl_closure *
uint32_t size, wl_connection_demarshal(struct wl_connection *connection,
struct wl_hash_table *objects, uint32_t size,
void (*func)(void), struct wl_hash_table *objects,
void *data, struct wl_object *target, const struct wl_message *message);
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 #endif

@ -340,6 +340,8 @@ handle_event(struct wl_display *display,
uint32_t p[32]; uint32_t p[32];
struct wl_listener *listener; struct wl_listener *listener;
struct wl_proxy *proxy; struct wl_proxy *proxy;
struct wl_closure *closure;
struct wl_message *message;
wl_connection_copy(display->connection, p, size); wl_connection_copy(display->connection, p, size);
if (id == 1) if (id == 1)
@ -347,17 +349,21 @@ handle_event(struct wl_display *display,
else else
proxy = wl_hash_table_lookup(display->objects, id); proxy = wl_hash_table_lookup(display->objects, id);
if (proxy != NULL) if (proxy == NULL) {
wl_list_for_each(listener, &proxy->listener_list, link) wl_connection_consume(display->connection, size);
wl_connection_demarshal(display->connection, return;
size, }
display->objects,
listener->implementation[opcode], message = &proxy->base.interface->events[opcode];
listener->data, closure = wl_connection_demarshal(display->connection,
&proxy->base, size, display->objects, message);
&proxy->base.interface->events[opcode]);
wl_list_for_each(listener, &proxy->listener_list, link)
wl_connection_consume(display->connection, size); wl_closure_invoke(closure, &proxy->base,
listener->implementation[opcode],
listener->data);
wl_closure_destroy(closure);
} }
WL_EXPORT void WL_EXPORT void

@ -86,9 +86,11 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
struct wl_client *client = data; struct wl_client *client = data;
struct wl_connection *connection = client->connection; struct wl_connection *connection = client->connection;
struct wl_object *object; struct wl_object *object;
struct wl_closure *closure;
const struct wl_message *message;
uint32_t p[2], opcode, size; uint32_t p[2], opcode, size;
uint32_t cmask = 0; uint32_t cmask = 0;
int len, ret; int len;
if (mask & WL_EVENT_READABLE) if (mask & WL_EVENT_READABLE)
cmask |= WL_CONNECTION_READABLE; cmask |= WL_CONNECTION_READABLE;
@ -125,24 +127,28 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
continue; continue;
} }
ret = wl_connection_demarshal(client->connection, message = &object->interface->methods[opcode];
size, closure = wl_connection_demarshal(client->connection, size,
client->display->objects, client->display->objects,
object->implementation[opcode], message);
client, len -= size;
object,
&object->interface->methods[opcode]);
if (ret < 0 && errno == EINVAL) if (closure == NULL && errno == EINVAL) {
wl_client_post_event(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_INVALID_METHOD, WL_DISPLAY_INVALID_METHOD,
p[0], opcode); p[0], opcode);
if (ret < 0 && errno == ENOMEM) continue;
} else if (closure == NULL && errno == ENOMEM) {
wl_client_post_event(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_NO_MEMORY); 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;
} }
} }

Loading…
Cancel
Save