SDL: configure/cmake: Hook up Emscripten threads (disabled by default).

From a81fe27271b484b99b19bd7e96394dec1f2a4f38 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 4 Apr 2021 00:16:30 -0400
Subject: [PATCH] configure/cmake: Hook up Emscripten threads (disabled by
 default).

Fixes #3795.
---
 CMakeLists.txt        | 18 +++++++--
 cmake/sdlchecks.cmake |  3 ++
 configure             | 93 +++++++++++++++++++++++--------------------
 configure.ac          | 39 ++++++++++++++++--
 4 files changed, 103 insertions(+), 50 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fef44774..68041078c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -153,7 +153,14 @@ else()
   set(UNIX_OR_MAC_SYS OFF)
 endif()
 
-if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN) # JavaScript does not yet have threading support, so disable pthreads when building for Emscripten.
+# Emscripten pthreads work, but you need to have a non-pthread fallback build
+#  for systems without support. It's not currently enough to not use
+#  pthread functions in a pthread-build; it won't start up on unsupported
+#  browsers. As such, you have to explicitly enable it on Emscripten builds
+#  for the time being. This default with change to ON once this becomes
+#  commonly supported in browsers or the Emscripten teams makes a single
+#  binary work everywhere.
+if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN)
   set(SDL_PTHREADS_ENABLED_BY_DEFAULT ON)
 else()
   set(SDL_PTHREADS_ENABLED_BY_DEFAULT OFF)
@@ -289,11 +296,14 @@ set(OPT_DEF_ASM TRUE)
 if(EMSCRIPTEN)
   # Set up default values for the currently supported set of subsystems:
   # Emscripten/Javascript does not have assembly support, a dynamic library
-  # loading architecture, low-level CPU inspection or multithreading.
+  # loading architecture, or low-level CPU inspection.
+
+  # SDL_THREADS_ENABLED_BY_DEFAULT now defaults to ON, but pthread support might be disabled by default.
+  # !!! FIXME: most of these subsystems should default to ON if there are dummy implementations to be used.
+
   set(OPT_DEF_ASM FALSE)
   set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
   set(SDL_ATOMIC_ENABLED_BY_DEFAULT OFF)
-  set(SDL_THREADS_ENABLED_BY_DEFAULT OFF)
   set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF)
   set(SDL_CPUINFO_ENABLED_BY_DEFAULT OFF)
   set(SDL_DLOPEN_ENABLED_BY_DEFAULT OFF)
@@ -1154,6 +1164,8 @@ elseif(EMSCRIPTEN)
     endif()
   endif()
 
+  CheckPTHREAD()
+
 elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS)
   if(SDL_AUDIO)
     if(SYSV5 OR SOLARIS OR HPUX)
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 64089c6bd..9e05497e9 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -919,6 +919,9 @@ macro(CheckPTHREAD)
     elseif(HAIKU)
       set(PTHREAD_CFLAGS "-D_REENTRANT")
       set(PTHREAD_LDFLAGS "")
+    elseif(EMSCRIPTEN)
+      set(PTHREAD_CFLAGS "-D_REENTRANT -pthread")
+      set(PTHREAD_LDFLAGS "-pthread")
     else()
       set(PTHREAD_CFLAGS "-D_REENTRANT")
       set(PTHREAD_LDFLAGS "-lpthread")
diff --git a/configure b/configure
index b1a6c2429..0daa8a1f1 100755
--- a/configure
+++ b/configure
@@ -771,6 +771,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -986,6 +987,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1238,6 +1240,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1375,7 +1386,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1528,6 +1539,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1682,8 +1694,9 @@ Optional Features:
   --enable-ibus           enable IBus support [default=yes]
   --enable-fcitx          enable fcitx support [default=yes]
   --enable-joystick-mfi   include macOS MFI joystick support [default=yes]
-  --enable-pthreads       use POSIX threads for multi-threading [default=yes]
-  --enable-pthread-sem    use pthread semaphores [default=yes]
+  --enable-pthreads       use POSIX threads for multi-threading
+                          [default=maybe]
+  --enable-pthread-sem    use pthread semaphores [default=maybe]
   --enable-directx        use DirectX for Windows audio/video [default=yes]
   --enable-xinput         use Xinput for Windows [default=yes]
   --enable-wasapi         use the Windows WASAPI audio driver [default=yes]
@@ -20257,34 +20270,8 @@ else
   $as_echo_n "(cached) " >&6
 else
   # One or both of the vars are not set, and there is no cached value.
-ac_x_includes=no
-ac_x_libraries=no
-# Do we need to do anything special at all?
-ac_save_LIBS=$LIBS
-LIBS="-lX11 $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <X11/Xlib.h>
-int
-main ()
-{
-XrmInitialize ()
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  # We can compile and link X programs with no special options.
-  ac_x_includes=
-  ac_x_libraries=
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS="$ac_save_LIBS"
-# If that didn't work, only try xmkmf and filesystem searches
-# for native compilation.
-if test x"$ac_x_includes" = xno && test "$cross_compiling" = no; then :
-  rm -f -r conftest.dir
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
 if mkdir conftest.dir; then
   cd conftest.dir
   cat >Imakefile <<'_ACEOF'
@@ -20323,7 +20310,7 @@ _ACEOF
   rm -f -r conftest.dir
 fi
 
-  # Standard set of common directories for X headers.
+# Standard set of common directories for X headers.
 # Check X11 before X11Rn because it is often a symlink to the current release.
 ac_x_header_dirs='
 /usr/X11/include
@@ -20350,8 +20337,6 @@ ac_x_header_dirs='
 /usr/local/include/X11R5
 /usr/local/include/X11R4
 
-/opt/X11/include
-
 /usr/X386/include
 /usr/x386/include
 /usr/XFree86/include/X11
@@ -20425,17 +20410,15 @@ rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 fi # $ac_x_libraries = no
 
-fi
-# Record the results.
 case $ac_x_includes,$ac_x_libraries in #(
-  no,* | *,no | *\'*) :
+  no,* | *,no | *\'*)
     # Didn't find X, or a directory has "'" in its name.
-    ac_cv_have_x="have_x=no" ;; #(
-  *) :
+    ac_cv_have_x="have_x=no";; #(
+  *)
     # Record where we found X for the cache.
     ac_cv_have_x="have_x=yes\
 	ac_x_includes='$ac_x_includes'\
-	ac_x_libraries='$ac_x_libraries'" ;;
+	ac_x_libraries='$ac_x_libraries'"
 esac
 fi
 ;; #(
@@ -23541,20 +23524,39 @@ $as_echo "#define SDL_JOYSTICK_MFI 1" >>confdefs.h
 
 CheckPTHREAD()
 {
-        # Check whether --enable-pthreads was given.
+
+
+    case "$host" in
+        *-*-emscripten*)
+            enable_pthreads_default=no
+            ;;
+        *)
+            enable_pthreads_default=yes
+            ;;
+    esac
+
+    # Check whether --enable-pthreads was given.
 if test "${enable_pthreads+set}" = set; then :
   enableval=$enable_pthreads;
 else
-  enable_pthreads=yes
+  enable_pthreads=maybe
 fi
 
         # Check whether --enable-pthread-sem was given.
 if test "${enable_pthread_sem+set}" = set; then :
   enableval=$enable_pthread_sem;
 else
-  enable_pthread_sem=yes
+  enable_pthread_sem=maybe
 fi
 
+
+    if test x$enable_pthreads = xmaybe; then
+        enable_pthreads=$enable_pthreads_default
+    fi
+    if test x$enable_pthread_sem = xmaybe; then
+        enable_pthread_sem=$enable_pthreads
+    fi
+
     case "$host" in
          *-*-android*)
             pthread_cflags="-D_REENTRANT -D_THREAD_SAFE"
@@ -23620,6 +23622,10 @@ fi
             pthread_cflags="-D_REENTRANT"
             pthread_lib=""
             ;;
+        *-*-emscripten*)
+            pthread_cflags="-D_REENTRANT -pthread"
+            pthread_lib="-pthread"
+            ;;
         *)
             pthread_cflags="-D_REENTRANT"
             pthread_lib="-lpthread"
@@ -25868,6 +25874,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_EMSCRIPTEN 1" >>confdefs.h
         CheckDummyVideo
         CheckDiskAudio
         CheckDummyAudio
+        CheckPTHREAD
         CheckDLOPEN
         CheckClockGettime
         CheckEmscriptenGLES
diff --git a/configure.ac b/configure.ac
index e28996695..5e583e09f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2941,13 +2941,39 @@ dnl See what type of thread model to use on Linux and Solaris
 CheckPTHREAD()
 {
     dnl Check for pthread support
+
+    dnl Emscripten pthreads work, but you need to have a non-pthread fallback build
+    dnl  for systems without support. It's not currently enough to not use
+    dnl  pthread functions in a pthread-build; it won't start up on unsupported
+    dnl  browsers. As such, you have to explicitly enable it on Emscripten builds
+    dnl  for the time being. This default with change to ON once this becomes
+    dnl  commonly supported in browsers or the Emscripten teams makes a single
+    dnl  binary work everywhere.
+
+    case "$host" in
+        *-*-emscripten*)
+            enable_pthreads_default=no
+            ;;
+        *)
+            enable_pthreads_default=yes
+            ;;
+    esac
+
     AC_ARG_ENABLE(pthreads,
-[AS_HELP_STRING([--enable-pthreads], [use POSIX threads for multi-threading [default=yes]])],
-                  , enable_pthreads=yes)
+[AS_HELP_STRING([--enable-pthreads], [use POSIX threads for multi-threading [default=maybe]])],
+                  , enable_pthreads=maybe)
     dnl This is used on Linux for glibc binary compatibility (Doh!)
     AC_ARG_ENABLE(pthread-sem,
-[AS_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [default=yes]])],
-                  , enable_pthread_sem=yes)
+[AS_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [default=maybe]])],
+                  , enable_pthread_sem=maybe)
+
+    if test x$enable_pthreads = xmaybe; then
+        enable_pthreads=$enable_pthreads_default
+    fi
+    if test x$enable_pthread_sem = xmaybe; then
+        enable_pthread_sem=$enable_pthreads
+    fi
+
     case "$host" in
          *-*-android*)
             pthread_cflags="-D_REENTRANT -D_THREAD_SAFE"
@@ -3013,6 +3039,10 @@ CheckPTHREAD()
             pthread_cflags="-D_REENTRANT"
             pthread_lib=""
             ;;
+        *-*-emscripten*)
+            pthread_cflags="-D_REENTRANT -pthread"
+            pthread_lib="-pthread"
+            ;;
         *)
             pthread_cflags="-D_REENTRANT"
             pthread_lib="-lpthread"
@@ -4302,6 +4332,7 @@ case "$host" in
         CheckDummyVideo
         CheckDiskAudio
         CheckDummyAudio
+        CheckPTHREAD
         CheckDLOPEN
         CheckClockGettime
         CheckEmscriptenGLES