summaryrefslogtreecommitdiffstats
path: root/src/egl/drivers/dri2
diff options
context:
space:
mode:
authorJonas Ådahl <[email protected]>2017-01-13 23:05:10 +0800
committerEmil Velikov <[email protected]>2017-01-13 15:50:37 +0000
commit36b9976e1f99e8070c67cb8a255793939db77d02 (patch)
tree832df6b0f68d15f000840a14092ccfe6a516003c /src/egl/drivers/dri2
parent361796651c5abb21ff429466c061119dce8f33d5 (diff)
egl/wayland: Avoid race conditions when on non-main thread
When EGL is used on some other thread than the thread that drives the main wl_display queue, the Wayland EGL dri2 implementation is vulnerable to a race condition related to display round trips and global object advertisements. The race that may happen is that after after a proxy is created, but before the queue is set, events meant to be emitted via the yet to be set queue may already have been queued on the wrong queue. In order to make it possible to avoid this race, wayland 1.11 introduced new API that allows creating a proxy wrapper that may be used as the factory proxy when creating new proxies via Wayland requests. The queue of a proxy wrapper can be changed without effecting what queue events emitted by the actual proxy will be queued on, while still effecting what default queue proxies created from it will have. By introducing a wl_display proxy wrapper and using this when performing round trips (via wl_display_sync()) and retrieving the global objects (via wl_display_get_registry()), the mentioned race condition is avoided. Signed-off-by: Jonas Ådahl <[email protected]> Cc: [email protected] Reviewed-by: Daniel Stone <[email protected]>
Diffstat (limited to 'src/egl/drivers/dri2')
-rw-r--r--src/egl/drivers/dri2/egl_dri2.c1
-rw-r--r--src/egl/drivers/dri2/egl_dri2.h1
-rw-r--r--src/egl/drivers/dri2/platform_wayland.c37
3 files changed, 25 insertions, 14 deletions
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 52fbdff0b12..cf72a7e44cc 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -914,6 +914,7 @@ dri2_display_release(_EGLDisplay *disp)
wl_shm_destroy(dri2_dpy->wl_shm);
wl_registry_destroy(dri2_dpy->wl_registry);
wl_event_queue_destroy(dri2_dpy->wl_queue);
+ wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
if (dri2_dpy->own_device) {
wl_display_disconnect(dri2_dpy->wl_dpy);
}
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index eac58f3cbf3..f3437e2b5a2 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -208,6 +208,7 @@ struct dri2_egl_display
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_display *wl_dpy;
+ struct wl_display *wl_dpy_wrapper;
struct wl_registry *wl_registry;
struct wl_drm *wl_server_drm;
struct wl_drm *wl_drm;
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 2b50d8ec949..17ff68479fd 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -74,9 +74,8 @@ roundtrip(struct dri2_egl_display *dri2_dpy)
struct wl_callback *callback;
int done = 0, ret = 0;
- callback = wl_display_sync(dri2_dpy->wl_dpy);
+ callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
wl_callback_add_listener(callback, &sync_listener, &done);
- wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
while (ret != -1 && !done)
ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
@@ -780,11 +779,9 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
* handle the commit and send a release event before checking for a free
* buffer */
if (dri2_surf->throttle_callback == NULL) {
- dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
+ dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
wl_callback_add_listener(dri2_surf->throttle_callback,
&throttle_listener, dri2_surf);
- wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
- dri2_dpy->wl_queue);
}
wl_display_flush(dri2_dpy->wl_dpy);
@@ -1159,12 +1156,17 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
+ dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
+ if (dri2_dpy->wl_dpy_wrapper == NULL)
+ goto cleanup_dpy_wrapper;
+
+ wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
+ dri2_dpy->wl_queue);
+
if (dri2_dpy->own_device)
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
- dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
- wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
- dri2_dpy->wl_queue);
+ dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
wl_registry_add_listener(dri2_dpy->wl_registry,
&registry_listener_drm, dri2_dpy);
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
@@ -1282,6 +1284,8 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
wl_drm_destroy(dri2_dpy->wl_drm);
cleanup_registry:
wl_registry_destroy(dri2_dpy->wl_registry);
+ wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
+ cleanup_dpy_wrapper:
wl_event_queue_destroy(dri2_dpy->wl_queue);
if (disp->PlatformDisplay == NULL)
wl_display_disconnect(dri2_dpy->wl_dpy);
@@ -1595,11 +1599,9 @@ dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
* handle the commit and send a release event before checking for a free
* buffer */
if (dri2_surf->throttle_callback == NULL) {
- dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
+ dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
wl_callback_add_listener(dri2_surf->throttle_callback,
&throttle_listener, dri2_surf);
- wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
- dri2_dpy->wl_queue);
}
wl_display_flush(dri2_dpy->wl_dpy);
@@ -1875,12 +1877,17 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
+ dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
+ if (dri2_dpy->wl_dpy_wrapper == NULL)
+ goto cleanup_dpy_wrapper;
+
+ wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
+ dri2_dpy->wl_queue);
+
if (dri2_dpy->own_device)
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
- dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
- wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
- dri2_dpy->wl_queue);
+ dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
wl_registry_add_listener(dri2_dpy->wl_registry,
&registry_listener_swrast, dri2_dpy);
@@ -1922,6 +1929,8 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
wl_shm_destroy(dri2_dpy->wl_shm);
cleanup_registry:
wl_registry_destroy(dri2_dpy->wl_registry);
+ wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
+ cleanup_dpy_wrapper:
wl_event_queue_destroy(dri2_dpy->wl_queue);
if (disp->PlatformDisplay == NULL)
wl_display_disconnect(dri2_dpy->wl_dpy);