thread: Put all important SDL_CreateThread internal data into SDL_Thread.
authorRyan C. Gordon
Thu, 26 Mar 2020 22:14:59 -0400
changeset 13677498a7f27758e
parent 13676 9c0592cc3e92
child 13678 682e469ffeed
thread: Put all important SDL_CreateThread internal data into SDL_Thread.

This avoids the need to malloc something extra, use a semaphore, etc, and
fixes Emscripten with pthreads support, which might not spin up a web worker
until after SDL_CreateThread returns and thus can't wait on a semaphore at
this point in any case.

Fixes Bugzilla #5064.
src/thread/SDL_systhread.h
src/thread/SDL_thread.c
src/thread/SDL_thread_c.h
src/thread/generic/SDL_systhread.c
src/thread/psp/SDL_systhread.c
src/thread/pthread/SDL_systhread.c
src/thread/stdcpp/SDL_systhread.cpp
src/thread/windows/SDL_systhread.c
     1.1 --- a/src/thread/SDL_systhread.h	Thu Mar 26 19:30:17 2020 -0700
     1.2 +++ b/src/thread/SDL_systhread.h	Thu Mar 26 22:14:59 2020 -0400
     1.3 @@ -33,11 +33,11 @@
     1.4     on success.
     1.5  */
     1.6  #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
     1.7 -extern int SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
     1.8 +extern int SDL_SYS_CreateThread(SDL_Thread * thread,
     1.9                                  pfnSDL_CurrentBeginThread pfnBeginThread,
    1.10                                  pfnSDL_CurrentEndThread pfnEndThread);
    1.11  #else
    1.12 -extern int SDL_SYS_CreateThread(SDL_Thread * thread, void *args);
    1.13 +extern int SDL_SYS_CreateThread(SDL_Thread * thread);
    1.14  #endif
    1.15  
    1.16  /* This function does any necessary setup in the child thread */
     2.1 --- a/src/thread/SDL_thread.c	Thu Mar 26 19:30:17 2020 -0700
     2.2 +++ b/src/thread/SDL_thread.c	Thu Mar 26 22:14:59 2020 -0400
     2.3 @@ -258,22 +258,12 @@
     2.4  }
     2.5  
     2.6  
     2.7 -/* Arguments and callback to setup and run the user thread function */
     2.8 -typedef struct
     2.9 +void
    2.10 +SDL_RunThread(SDL_Thread *thread)
    2.11  {
    2.12 -    int (SDLCALL * func) (void *);
    2.13 -    void *data;
    2.14 -    SDL_Thread *info;
    2.15 -    SDL_sem *wait;
    2.16 -} thread_args;
    2.17 +    void *userdata = thread->userdata;
    2.18 +    int (SDLCALL * userfunc) (void *) = thread->userfunc;
    2.19  
    2.20 -void
    2.21 -SDL_RunThread(void *data)
    2.22 -{
    2.23 -    thread_args *args = (thread_args *) data;
    2.24 -    int (SDLCALL * userfunc) (void *) = args->func;
    2.25 -    void *userdata = args->data;
    2.26 -    SDL_Thread *thread = args->info;
    2.27      int *statusloc = &thread->status;
    2.28  
    2.29      /* Perform any system-dependent setup - this function may not fail */
    2.30 @@ -282,9 +272,6 @@
    2.31      /* Get the thread id */
    2.32      thread->threadid = SDL_ThreadID();
    2.33  
    2.34 -    /* Wake up the parent thread */
    2.35 -    SDL_SemPost(args->wait);
    2.36 -
    2.37      /* Run the function */
    2.38      *statusloc = userfunc(userdata);
    2.39  
    2.40 @@ -325,16 +312,14 @@
    2.41  #endif
    2.42  {
    2.43      SDL_Thread *thread;
    2.44 -    thread_args *args;
    2.45      int ret;
    2.46  
    2.47      /* Allocate memory for the thread info structure */
    2.48 -    thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
    2.49 +    thread = (SDL_Thread *) SDL_calloc(1, sizeof(*thread));
    2.50      if (thread == NULL) {
    2.51          SDL_OutOfMemory();
    2.52 -        return (NULL);
    2.53 +        return NULL;
    2.54      }
    2.55 -    SDL_zerop(thread);
    2.56      thread->status = -1;
    2.57      SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
    2.58  
    2.59 @@ -344,57 +329,29 @@
    2.60          if (thread->name == NULL) {
    2.61              SDL_OutOfMemory();
    2.62              SDL_free(thread);
    2.63 -            return (NULL);
    2.64 +            return NULL;
    2.65          }
    2.66      }
    2.67  
    2.68 -    /* Set up the arguments for the thread */
    2.69 -    args = (thread_args *) SDL_malloc(sizeof(*args));
    2.70 -    if (args == NULL) {
    2.71 -        SDL_OutOfMemory();
    2.72 -        if (thread->name) {
    2.73 -            SDL_free(thread->name);
    2.74 -        }
    2.75 -        SDL_free(thread);
    2.76 -        return (NULL);
    2.77 -    }
    2.78 -    args->func = fn;
    2.79 -    args->data = data;
    2.80 -    args->info = thread;
    2.81 -    args->wait = SDL_CreateSemaphore(0);
    2.82 -    if (args->wait == NULL) {
    2.83 -        if (thread->name) {
    2.84 -            SDL_free(thread->name);
    2.85 -        }
    2.86 -        SDL_free(thread);
    2.87 -        SDL_free(args);
    2.88 -        return (NULL);
    2.89 -    }
    2.90 -
    2.91 +    thread->userfunc = fn;
    2.92 +    thread->userdata = data;
    2.93      thread->stacksize = stacksize;
    2.94  
    2.95      /* Create the thread and go! */
    2.96  #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
    2.97 -    ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
    2.98 +    ret = SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread);
    2.99  #else
   2.100 -    ret = SDL_SYS_CreateThread(thread, args);
   2.101 +    ret = SDL_SYS_CreateThread(thread);
   2.102  #endif
   2.103 -    if (ret >= 0) {
   2.104 -        /* Wait for the thread function to use arguments */
   2.105 -        SDL_SemWait(args->wait);
   2.106 -    } else {
   2.107 +    if (ret < 0) {
   2.108          /* Oops, failed.  Gotta free everything */
   2.109 -        if (thread->name) {
   2.110 -            SDL_free(thread->name);
   2.111 -        }
   2.112 +        SDL_free(thread->name);
   2.113          SDL_free(thread);
   2.114          thread = NULL;
   2.115      }
   2.116 -    SDL_DestroySemaphore(args->wait);
   2.117 -    SDL_free(args);
   2.118  
   2.119      /* Everything is running now */
   2.120 -    return (thread);
   2.121 +    return thread;
   2.122  }
   2.123  
   2.124  #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
     3.1 --- a/src/thread/SDL_thread_c.h	Thu Mar 26 19:30:17 2020 -0700
     3.2 +++ b/src/thread/SDL_thread_c.h	Thu Mar 26 22:14:59 2020 -0400
     3.3 @@ -60,11 +60,14 @@
     3.4      SDL_error errbuf;
     3.5      char *name;
     3.6      size_t stacksize;  /* 0 for default, >0 for user-specified stack size. */
     3.7 +    int (SDLCALL * userfunc) (void *);
     3.8 +    void *userdata;
     3.9      void *data;
    3.10 +    void *endfunc;  /* only used on some platforms. */
    3.11  };
    3.12  
    3.13  /* This is the function called to run a thread */
    3.14 -extern void SDL_RunThread(void *data);
    3.15 +extern void SDL_RunThread(SDL_Thread *thread);
    3.16  
    3.17  /* This is the system-independent thread local storage structure */
    3.18  typedef struct {
     4.1 --- a/src/thread/generic/SDL_systhread.c	Thu Mar 26 19:30:17 2020 -0700
     4.2 +++ b/src/thread/generic/SDL_systhread.c	Thu Mar 26 22:14:59 2020 -0400
     4.3 @@ -27,12 +27,12 @@
     4.4  
     4.5  #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
     4.6  int
     4.7 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
     4.8 +SDL_SYS_CreateThread(SDL_Thread * thread,
     4.9                       pfnSDL_CurrentBeginThread pfnBeginThread,
    4.10                       pfnSDL_CurrentEndThread pfnEndThread)
    4.11  #else
    4.12  int
    4.13 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    4.14 +SDL_SYS_CreateThread(SDL_Thread * thread)
    4.15  #endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
    4.16  {
    4.17      return SDL_SetError("Threads are not supported on this platform");
     5.1 --- a/src/thread/psp/SDL_systhread.c	Thu Mar 26 19:30:17 2020 -0700
     5.2 +++ b/src/thread/psp/SDL_systhread.c	Thu Mar 26 22:14:59 2020 -0400
     5.3 @@ -37,11 +37,11 @@
     5.4  
     5.5  static int ThreadEntry(SceSize args, void *argp)
     5.6  {
     5.7 -    SDL_RunThread(*(void **) argp);
     5.8 +    SDL_RunThread(*(SDL_Thread **) argp);
     5.9      return 0;
    5.10  }
    5.11  
    5.12 -int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
    5.13 +int SDL_SYS_CreateThread(SDL_Thread *thread)
    5.14  {
    5.15      SceKernelThreadInfo status;
    5.16      int priority = 32;
    5.17 @@ -59,7 +59,7 @@
    5.18          return SDL_SetError("sceKernelCreateThread() failed");
    5.19      }
    5.20  
    5.21 -    sceKernelStartThread(thread->handle, 4, &args);
    5.22 +    sceKernelStartThread(thread->handle, 4, &thread);
    5.23      return 0;
    5.24  }
    5.25  
     6.1 --- a/src/thread/pthread/SDL_systhread.c	Thu Mar 26 19:30:17 2020 -0700
     6.2 +++ b/src/thread/pthread/SDL_systhread.c	Thu Mar 26 22:14:59 2020 -0400
     6.3 @@ -76,7 +76,7 @@
     6.4  #ifdef __ANDROID__
     6.5      Android_JNI_SetupThread();
     6.6  #endif
     6.7 -    SDL_RunThread(data);
     6.8 +    SDL_RunThread((SDL_Thread *) data);
     6.9      return NULL;
    6.10  }
    6.11  
    6.12 @@ -88,7 +88,7 @@
    6.13  static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
    6.14  #endif
    6.15  int
    6.16 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    6.17 +SDL_SYS_CreateThread(SDL_Thread * thread)
    6.18  {
    6.19      pthread_attr_t type;
    6.20  
    6.21 @@ -117,7 +117,7 @@
    6.22      }
    6.23  
    6.24      /* Create the thread and go! */
    6.25 -    if (pthread_create(&thread->handle, &type, RunThread, args) != 0) {
    6.26 +    if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
    6.27          return SDL_SetError("Not enough resources to create thread");
    6.28      }
    6.29  
     7.1 --- a/src/thread/stdcpp/SDL_systhread.cpp	Thu Mar 26 19:30:17 2020 -0700
     7.2 +++ b/src/thread/stdcpp/SDL_systhread.cpp	Thu Mar 26 22:14:59 2020 -0400
     7.3 @@ -40,16 +40,16 @@
     7.4  static void
     7.5  RunThread(void *args)
     7.6  {
     7.7 -    SDL_RunThread(args);
     7.8 +    SDL_RunThread((SDL_Thread *) args);
     7.9  }
    7.10  
    7.11  extern "C"
    7.12  int
    7.13 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    7.14 +SDL_SYS_CreateThread(SDL_Thread * thread)
    7.15  {
    7.16      try {
    7.17          // !!! FIXME: no way to set a thread stack size here.
    7.18 -        std::thread cpp_thread(RunThread, args);
    7.19 +        std::thread cpp_thread(RunThread, thread);
    7.20          thread->handle = (void *) new std::thread(std::move(cpp_thread));
    7.21          return 0;
    7.22      } catch (std::system_error & ex) {
     8.1 --- a/src/thread/windows/SDL_systhread.c	Thu Mar 26 19:30:17 2020 -0700
     8.2 +++ b/src/thread/windows/SDL_systhread.c	Thu Mar 26 22:14:59 2020 -0400
     8.3 @@ -74,23 +74,16 @@
     8.4  #endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
     8.5  
     8.6  
     8.7 -typedef struct ThreadStartParms
     8.8 -{
     8.9 -    void *args;
    8.10 -    pfnSDL_CurrentEndThread pfnCurrentEndThread;
    8.11 -} tThreadStartParms, *pThreadStartParms;
    8.12 -
    8.13  static DWORD
    8.14  RunThread(void *data)
    8.15  {
    8.16 -    pThreadStartParms pThreadParms = (pThreadStartParms) data;
    8.17 -    pfnSDL_CurrentEndThread pfnEndThread = pThreadParms->pfnCurrentEndThread;
    8.18 -    void *args = pThreadParms->args;
    8.19 -    SDL_free(pThreadParms);
    8.20 -    SDL_RunThread(args);
    8.21 -    if (pfnEndThread != NULL)
    8.22 +    SDL_Thread *thread = (SDL_Thread *) data;
    8.23 +    pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread) thread->endfunc;
    8.24 +    SDL_RunThread(thread);
    8.25 +    if (pfnEndThread != NULL) {
    8.26          pfnEndThread(0);
    8.27 -    return (0);
    8.28 +    }
    8.29 +    return 0;
    8.30  }
    8.31  
    8.32  static DWORD WINAPI
    8.33 @@ -107,33 +100,27 @@
    8.34  
    8.35  #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
    8.36  int
    8.37 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
    8.38 +SDL_SYS_CreateThread(SDL_Thread * thread,
    8.39                       pfnSDL_CurrentBeginThread pfnBeginThread,
    8.40                       pfnSDL_CurrentEndThread pfnEndThread)
    8.41  {
    8.42  #elif defined(__CYGWIN__) || defined(__WINRT__)
    8.43  int
    8.44 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    8.45 +SDL_SYS_CreateThread(SDL_Thread * thread)
    8.46  {
    8.47      pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
    8.48      pfnSDL_CurrentEndThread pfnEndThread = NULL;
    8.49  #else
    8.50  int
    8.51 -SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
    8.52 +SDL_SYS_CreateThread(SDL_Thread * thread)
    8.53  {
    8.54      pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
    8.55      pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
    8.56  #endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
    8.57 -    pThreadStartParms pThreadParms =
    8.58 -        (pThreadStartParms) SDL_malloc(sizeof(tThreadStartParms));
    8.59      const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
    8.60 -    if (!pThreadParms) {
    8.61 -        return SDL_OutOfMemory();
    8.62 -    }
    8.63 +
    8.64      /* Save the function which we will have to call to clear the RTL of calling app! */
    8.65 -    pThreadParms->pfnCurrentEndThread = pfnEndThread;
    8.66 -    /* Also save the real parameters we have to pass to thread function */
    8.67 -    pThreadParms->args = args;
    8.68 +    thread->endfunc = pfnEndThread;
    8.69  
    8.70      /* thread->stacksize == 0 means "system default", same as win32 expects */
    8.71      if (pfnBeginThread) {
    8.72 @@ -141,12 +128,12 @@
    8.73          thread->handle = (SYS_ThreadHandle)
    8.74              ((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize,
    8.75                                       RunThreadViaBeginThreadEx,
    8.76 -                                     pThreadParms, flags, &threadid));
    8.77 +                                     thread, flags, &threadid));
    8.78      } else {
    8.79          DWORD threadid = 0;
    8.80          thread->handle = CreateThread(NULL, thread->stacksize,
    8.81                                        RunThreadViaCreateThread,
    8.82 -                                      pThreadParms, flags, &threadid);
    8.83 +                                      thread, flags, &threadid);
    8.84      }
    8.85      if (thread->handle == NULL) {
    8.86          return SDL_SetError("Not enough resources to create thread");