summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Engestrom <eric@engestrom.ch>2017-06-15 23:53:55 +0100
committerEric Engestrom <eric.engestrom@imgtec.com>2017-06-16 11:02:06 +0100
commit311c09165881111c4a596ca7e7b4bce89b059e0f (patch)
treebe935fe7fb1f35ff106198a2829cd685f609225f
parent4ca9ae587c083b6f03feb65b4ce84929109d5d59 (diff)
egl/display: make platform detection thread-safe
Imagine there are 2 threads that both call _eglGetNativePlatform() simultaneously: - thread 1 completes the first "if (native_platform == _EGL_INVALID_PLATFORM)" check and is preempted to do something else - thread 2 executes the whole function, does "native_platform = _EGL_NATIVE_PLATFORM" and just before returning it's preempted - thread 1 wakes up and calls _eglGetNativePlatformFromEnv() which returns _EGL_INVALID_PLATFORM because no env vars are set, updates native_platform and then gets preempted again - thread 2 wakes up and returns wrong _EGL_INVALID_PLATFORM Solve this by doing the detection in a local var and only overwriting the global one at the end, if no other thread has updated it since. This means the platform detected in the thread might not be the platform returned by the function, but this is a different issue that will need to be discussed when this becomes possible. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101252 Signed-off-by: Eric Engestrom <eric@engestrom.ch> Reviewed-by: Grazvydas Ignotas <notasas@gmail.com> Acked-by: Emil Velikov <emil.l.velikov@gmail.com>
-rw-r--r--src/egl/main/egldisplay.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 53c6e6346d7..6eeaa35eb63 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
#include "c11/threads.h"
+#include "util/u_atomic.h"
#include "eglcontext.h"
#include "eglcurrent.h"
@@ -181,25 +182,29 @@ _EGLPlatformType
_eglGetNativePlatform(void *nativeDisplay)
{
static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
+ _EGLPlatformType detected_platform = native_platform;
- if (native_platform == _EGL_INVALID_PLATFORM) {
+ if (detected_platform == _EGL_INVALID_PLATFORM) {
const char *detection_method;
- native_platform = _eglGetNativePlatformFromEnv();
+ detected_platform = _eglGetNativePlatformFromEnv();
detection_method = "environment overwrite";
- if (native_platform == _EGL_INVALID_PLATFORM) {
- native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
+ if (detected_platform == _EGL_INVALID_PLATFORM) {
+ detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
detection_method = "autodetected";
}
- if (native_platform == _EGL_INVALID_PLATFORM) {
- native_platform = _EGL_NATIVE_PLATFORM;
+ if (detected_platform == _EGL_INVALID_PLATFORM) {
+ detected_platform = _EGL_NATIVE_PLATFORM;
detection_method = "build-time configuration";
}
_eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
- egl_platforms[native_platform].name, detection_method);
+ egl_platforms[detected_platform].name, detection_method);
+
+ p_atomic_cmpxchg(&native_platform, _EGL_INVALID_PLATFORM,
+ detected_platform);
}
return native_platform;