SDL: log: Wrap the call to the logging implementation in a mutex.

From c4141bc11c3d86d41a28da6418bb36a8f9668035 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 27 Apr 2022 09:39:24 -0400
Subject: [PATCH] log: Wrap the call to the logging implementation in a mutex.

Fixes #2463.
---
 src/SDL.c     |  8 +++++++-
 src/SDL_log.c | 25 +++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/SDL.c b/src/SDL.c
index 68a4f5da2c0..08fed1ea4d9 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -147,6 +147,9 @@ SDL_SetMainReady(void)
     SDL_MainIsReady = SDL_TRUE;
 }
 
+void SDL_LogInit(void);
+void SDL_LogQuit(void);
+
 int
 SDL_InitSubSystem(Uint32 flags)
 {
@@ -156,6 +159,8 @@ SDL_InitSubSystem(Uint32 flags)
         return SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?");
     }
 
+    SDL_LogInit();
+
     /* Clear the error message */
     SDL_ClearError();
 
@@ -470,12 +475,13 @@ SDL_Quit(void)
 
     SDL_ClearHints();
     SDL_AssertionsQuit();
-    SDL_LogResetPriorities();
 
 #if SDL_USE_LIBDBUS
     SDL_DBus_Quit();
 #endif
 
+    SDL_LogQuit();
+
     /* Now that every subsystem has been quit, we reset the subsystem refcount
      * and the list of initialized subsystems.
      */
diff --git a/src/SDL_log.c b/src/SDL_log.c
index dfbaca499d3..b31574da994 100644
--- a/src/SDL_log.c
+++ b/src/SDL_log.c
@@ -28,6 +28,7 @@
 
 #include "SDL_error.h"
 #include "SDL_log.h"
+#include "SDL_mutex.h"
 
 #if HAVE_STDIO_H
 #include <stdio.h>
@@ -59,6 +60,7 @@ static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
 static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
 static void *SDL_log_userdata = NULL;
+static SDL_mutex *log_function_mutex = NULL;
 
 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
     NULL,
@@ -92,6 +94,24 @@ static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
 };
 #endif /* __ANDROID__ */
 
+void
+SDL_LogInit(void)
+{
+    if (!log_function_mutex) {
+        /* if this fails we'll try to continue without it. */
+        log_function_mutex = SDL_CreateMutex();
+    }
+}
+
+void
+SDL_LogQuit(void)
+{
+    SDL_LogResetPriorities();
+    if (log_function_mutex) {
+        SDL_DestroyMutex(log_function_mutex);
+        log_function_mutex = NULL;
+    }
+}
 
 void
 SDL_LogSetAllPriority(SDL_LogPriority priority)
@@ -298,7 +318,12 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
         }
     }
 
+    /* this mutex creation can race if you log from two threads at startup. You should have called SDL_Init first! */
+    if (!log_function_mutex) { log_function_mutex = SDL_CreateMutex(); }
+    if (log_function_mutex) { SDL_LockMutex(log_function_mutex); }
     SDL_log_function(SDL_log_userdata, category, priority, message);
+    if (log_function_mutex) { SDL_UnlockMutex(log_function_mutex); }
+
     SDL_free(message);
 }