client: Split event handling into demarshal and dispatch steps

This lets us demarshal with a mutex held and then do dispatching after
releasing the mutex.
This commit is contained in:
Kristian Høgsberg 2012-10-04 17:34:18 -04:00
parent 53d24713a3
commit ce1f4c29ab
2 changed files with 49 additions and 20 deletions

View file

@ -499,22 +499,29 @@ create_proxies(struct wl_display *display, struct wl_closure *closure)
return 0;
}
static void
handle_event(struct wl_display *display,
uint32_t id, uint32_t opcode, uint32_t size)
static int
queue_event(struct wl_display *display, int len, struct wl_list *list)
{
uint32_t p[2], id;
int opcode, size;
struct wl_proxy *proxy;
struct wl_closure *closure;
const struct wl_message *message;
proxy = wl_map_lookup(&display->objects, id);
wl_connection_copy(display->connection, p, sizeof p);
id = p[0];
opcode = p[1] & 0xffff;
size = p[1] >> 16;
if (len < size)
return 0;
proxy = wl_map_lookup(&display->objects, id);
if (proxy == WL_ZOMBIE_OBJECT) {
wl_connection_consume(display->connection, size);
return;
return size;
} else if (proxy == NULL || proxy->object.implementation == NULL) {
wl_connection_consume(display->connection, size);
return;
return size;
}
message = &proxy->object.interface->events[opcode];
@ -529,40 +536,61 @@ handle_event(struct wl_display *display,
abort();
}
wl_list_insert(list->prev, &closure->link);
return size;
}
static void
dispatch_event(struct wl_display *display, struct wl_closure *closure)
{
struct wl_proxy *proxy;
uint32_t id;
int opcode;
wl_list_remove(&closure->link);
id = closure->buffer[0];
opcode = closure->buffer[1] & 0xffff;
proxy = wl_map_lookup(&display->objects, id);
if (proxy == WL_ZOMBIE_OBJECT)
goto skip;
wl_closure_invoke(closure, &proxy->object,
proxy->object.implementation[opcode],
proxy->user_data);
skip:
wl_closure_destroy(closure);
}
WL_EXPORT int
wl_display_dispatch(struct wl_display *display)
{
uint32_t p[2], object;
int len, opcode, size;
struct wl_list list;
struct wl_closure *closure;
int len, size;
/* FIXME: Handle flush errors, EAGAIN... */
wl_display_flush(display);
/* FIXME: Shouldn't always read here... */
len = wl_connection_read(display->connection);
if (len == -1)
return -1;
while (len > 0) {
if ((size_t) len < sizeof p)
wl_list_init(&list);
while (len >= 8) {
size = queue_event(display, len, &list);
if (size == 0)
break;
wl_connection_copy(display->connection, p, sizeof p);
object = p[0];
opcode = p[1] & 0xffff;
size = p[1] >> 16;
if (len < size)
break;
handle_event(display, object, opcode, size);
len -= size;
}
while (!wl_list_empty(&list)) {
closure = container_of(list.next, struct wl_closure, link);
dispatch_event(display, closure);
}
return len;
}

View file

@ -73,6 +73,7 @@ struct wl_closure {
ffi_cif cif;
void *args[20];
uint32_t *start;
struct wl_list link;
uint32_t buffer[0];
};