summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-10-25 22:17:54 +0200
committerwm4 <wm4@nowhere>2019-10-25 22:17:54 +0200
commitc184e290b0f7bbf9eb8a87c9e87c9aa870ca2c3f (patch)
tree08ad6a6cd52cc3d9659a1d1c2ec301e5c9b7672b
parente63091b3cc37978165a552b4d8ca63e6cb56f707 (diff)
downloadmpv-c184e290b0f7bbf9eb8a87c9e87c9aa870ca2c3f.tar.bz2
mpv-c184e290b0f7bbf9eb8a87c9e87c9aa870ca2c3f.tar.xz
sdl: prevent concurrent use of SDL in different threads
sdl_gamepad.c and vo_sdl.c both have their own event loops and run in separate threads. They don't know of each other (and shouldn't). Since SDL only has one global event loop (why didn't they fix this in SDL2?), these obviously clash. The actual behavior is relatively subtle, which event being randomly dispatched to either of the threads. This is very regrettable. Very. Work this around. "Fortunately" SDL exposes its global state to some degree. SDL_WasInit() returns whether a "subsystem" was initialized, and you could say the one who initialized it owns it. Both SDL_INIT_VIDEO and SDL_INIT_GAMECONTROLLER implicitly enable SDL_INIT_EVENTS, and the event loop is indeed the resource that cannot be shared. Unfortunately, this is still racy, since SDL_InitSubSystem is a second call, and succeeds if the subsystem is already initialized (increases a refcount I think). But good enough. Blame SDL for everything. (I think I made this commit message too long. Nobody cares even.) Fixes: #7085
-rw-r--r--input/sdl_gamepad.c8
-rw-r--r--video/out/vo_sdl.c4
2 files changed, 9 insertions, 3 deletions
diff --git a/input/sdl_gamepad.c b/input/sdl_gamepad.c
index 96b8409b49..7045239fda 100644
--- a/input/sdl_gamepad.c
+++ b/input/sdl_gamepad.c
@@ -198,11 +198,17 @@ static void remove_gamepad(struct mp_input_src *src, int id)
static void read_gamepad_thread(struct mp_input_src *src, void *param)
{
+ if (SDL_WasInit(SDL_INIT_EVENTS)) {
+ MP_ERR(src, "Another component is using SDL already.\n");
+ mp_input_src_init_done(src);
+ return;
+ }
+
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) {
MP_ERR(src, "SDL_Init failed\n");
mp_input_src_init_done(src);
return;
- };
+ }
pthread_once(&events_initialized, initialize_events);
diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c
index bd7e024585..9d21a87118 100644
--- a/video/out/vo_sdl.c
+++ b/video/out/vo_sdl.c
@@ -769,8 +769,8 @@ static int preinit(struct vo *vo)
{
struct priv *vc = vo->priv;
- if (SDL_WasInit(SDL_INIT_VIDEO)) {
- MP_ERR(vo, "already initialized\n");
+ if (SDL_WasInit(SDL_INIT_EVENTS)) {
+ MP_ERR(vo, "Another component is using SDL already.\n");
return -1;
}