client: Make wl_display thread safe

Not all entry points are thread safe: global listeners and global lookup
is still only main thread.
This commit is contained in:
Kristian Høgsberg 2012-10-04 17:42:49 -04:00
parent ce1f4c29ab
commit de961dc1f3

View file

@ -35,6 +35,7 @@
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/poll.h> #include <sys/poll.h>
#include <pthread.h>
#include "wayland-util.h" #include "wayland-util.h"
#include "wayland-os.h" #include "wayland-os.h"
@ -68,6 +69,7 @@ struct wl_display {
struct wl_map objects; struct wl_map objects;
struct wl_list global_listener_list; struct wl_list global_listener_list;
struct wl_list global_list; struct wl_list global_list;
pthread_mutex_t mutex;
wl_display_global_func_t global_handler; wl_display_global_func_t global_handler;
void *global_handler_data; void *global_handler_data;
@ -117,9 +119,12 @@ wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
proxy->object.interface = interface; proxy->object.interface = interface;
proxy->object.implementation = NULL; proxy->object.implementation = NULL;
proxy->display = display;
pthread_mutex_lock(&display->mutex);
proxy->object.id = wl_map_insert_new(&display->objects, proxy->object.id = wl_map_insert_new(&display->objects,
WL_MAP_CLIENT_SIDE, proxy); WL_MAP_CLIENT_SIDE, proxy);
proxy->display = display; pthread_mutex_unlock(&display->mutex);
return proxy; return proxy;
} }
@ -139,7 +144,10 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
proxy->object.implementation = NULL; proxy->object.implementation = NULL;
proxy->object.id = id; proxy->object.id = id;
proxy->display = display; proxy->display = display;
pthread_mutex_lock(&display->mutex);
wl_map_insert_at(&display->objects, id, proxy); wl_map_insert_at(&display->objects, id, proxy);
pthread_mutex_unlock(&display->mutex);
return proxy; return proxy;
} }
@ -147,12 +155,17 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
WL_EXPORT void WL_EXPORT void
wl_proxy_destroy(struct wl_proxy *proxy) wl_proxy_destroy(struct wl_proxy *proxy)
{ {
pthread_mutex_lock(&proxy->display->mutex);
if (proxy->object.id < WL_SERVER_ID_START) if (proxy->object.id < WL_SERVER_ID_START)
wl_map_insert_at(&proxy->display->objects, wl_map_insert_at(&proxy->display->objects,
proxy->object.id, WL_ZOMBIE_OBJECT); proxy->object.id, WL_ZOMBIE_OBJECT);
else else
wl_map_insert_at(&proxy->display->objects, wl_map_insert_at(&proxy->display->objects,
proxy->object.id, NULL); proxy->object.id, NULL);
pthread_mutex_unlock(&proxy->display->mutex);
free(proxy); free(proxy);
} }
@ -177,6 +190,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
struct wl_closure *closure; struct wl_closure *closure;
va_list ap; va_list ap;
pthread_mutex_lock(&proxy->display->mutex);
va_start(ap, opcode); va_start(ap, opcode);
closure = wl_closure_vmarshal(&proxy->object, opcode, ap, closure = wl_closure_vmarshal(&proxy->object, opcode, ap,
&proxy->object.interface->methods[opcode]); &proxy->object.interface->methods[opcode]);
@ -196,6 +211,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
} }
wl_closure_destroy(closure); wl_closure_destroy(closure);
pthread_mutex_unlock(&proxy->display->mutex);
} }
/* Can't do this, there may be more than one instance of an /* Can't do this, there may be more than one instance of an
@ -269,11 +286,15 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
{ {
struct wl_proxy *proxy; struct wl_proxy *proxy;
pthread_mutex_lock(&display->mutex);
proxy = wl_map_lookup(&display->objects, id); proxy = wl_map_lookup(&display->objects, id);
if (proxy != WL_ZOMBIE_OBJECT) if (proxy != WL_ZOMBIE_OBJECT)
fprintf(stderr, "server sent delete_id for live object\n"); fprintf(stderr, "server sent delete_id for live object\n");
else else
wl_map_remove(&display->objects, id); wl_map_remove(&display->objects, id);
pthread_mutex_unlock(&display->mutex);
} }
static const struct wl_display_listener display_listener = { static const struct wl_display_listener display_listener = {
@ -552,7 +573,10 @@ dispatch_event(struct wl_display *display, struct wl_closure *closure)
id = closure->buffer[0]; id = closure->buffer[0];
opcode = closure->buffer[1] & 0xffff; opcode = closure->buffer[1] & 0xffff;
pthread_mutex_lock(&display->mutex);
proxy = wl_map_lookup(&display->objects, id); proxy = wl_map_lookup(&display->objects, id);
pthread_mutex_unlock(&display->mutex);
if (proxy == WL_ZOMBIE_OBJECT) if (proxy == WL_ZOMBIE_OBJECT)
goto skip; goto skip;
@ -570,13 +594,17 @@ wl_display_dispatch(struct wl_display *display)
struct wl_closure *closure; struct wl_closure *closure;
int len, size; int len, size;
pthread_mutex_lock(&display->mutex);
/* FIXME: Handle flush errors, EAGAIN... */ /* FIXME: Handle flush errors, EAGAIN... */
wl_display_flush(display); wl_connection_flush(display->connection);
/* FIXME: Shouldn't always read here... */ /* FIXME: Shouldn't always read here... */
len = wl_connection_read(display->connection); len = wl_connection_read(display->connection);
if (len == -1) if (len == -1) {
pthread_mutex_unlock(&display->mutex);
return -1; return -1;
}
wl_list_init(&list); wl_list_init(&list);
while (len >= 8) { while (len >= 8) {
@ -586,6 +614,8 @@ wl_display_dispatch(struct wl_display *display)
len -= size; len -= size;
} }
pthread_mutex_unlock(&display->mutex);
while (!wl_list_empty(&list)) { while (!wl_list_empty(&list)) {
closure = container_of(list.next, struct wl_closure, link); closure = container_of(list.next, struct wl_closure, link);
dispatch_event(display, closure); dispatch_event(display, closure);
@ -597,7 +627,15 @@ wl_display_dispatch(struct wl_display *display)
WL_EXPORT int WL_EXPORT int
wl_display_flush(struct wl_display *display) wl_display_flush(struct wl_display *display)
{ {
return wl_connection_flush(display->connection); int ret;
pthread_mutex_lock(&display->mutex);
ret = wl_connection_flush(display->connection);
pthread_mutex_unlock(&display->mutex);
return ret;
} }
WL_EXPORT void * WL_EXPORT void *