mirror of https://github.com/encounter/SDL.git
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.
This commit is contained in:
parent
abdc5cbf24
commit
46bb47cf04
|
@ -33,11 +33,11 @@
|
||||||
on success.
|
on success.
|
||||||
*/
|
*/
|
||||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||||
extern int SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
|
extern int SDL_SYS_CreateThread(SDL_Thread * thread,
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread,
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
pfnSDL_CurrentEndThread pfnEndThread);
|
pfnSDL_CurrentEndThread pfnEndThread);
|
||||||
#else
|
#else
|
||||||
extern int SDL_SYS_CreateThread(SDL_Thread * thread, void *args);
|
extern int SDL_SYS_CreateThread(SDL_Thread * thread);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This function does any necessary setup in the child thread */
|
/* This function does any necessary setup in the child thread */
|
||||||
|
|
|
@ -258,22 +258,12 @@ SDL_GetErrBuf(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Arguments and callback to setup and run the user thread function */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int (SDLCALL * func) (void *);
|
|
||||||
void *data;
|
|
||||||
SDL_Thread *info;
|
|
||||||
SDL_sem *wait;
|
|
||||||
} thread_args;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SDL_RunThread(void *data)
|
SDL_RunThread(SDL_Thread *thread)
|
||||||
{
|
{
|
||||||
thread_args *args = (thread_args *) data;
|
void *userdata = thread->userdata;
|
||||||
int (SDLCALL * userfunc) (void *) = args->func;
|
int (SDLCALL * userfunc) (void *) = thread->userfunc;
|
||||||
void *userdata = args->data;
|
|
||||||
SDL_Thread *thread = args->info;
|
|
||||||
int *statusloc = &thread->status;
|
int *statusloc = &thread->status;
|
||||||
|
|
||||||
/* Perform any system-dependent setup - this function may not fail */
|
/* Perform any system-dependent setup - this function may not fail */
|
||||||
|
@ -282,9 +272,6 @@ SDL_RunThread(void *data)
|
||||||
/* Get the thread id */
|
/* Get the thread id */
|
||||||
thread->threadid = SDL_ThreadID();
|
thread->threadid = SDL_ThreadID();
|
||||||
|
|
||||||
/* Wake up the parent thread */
|
|
||||||
SDL_SemPost(args->wait);
|
|
||||||
|
|
||||||
/* Run the function */
|
/* Run the function */
|
||||||
*statusloc = userfunc(userdata);
|
*statusloc = userfunc(userdata);
|
||||||
|
|
||||||
|
@ -325,16 +312,14 @@ SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
thread_args *args;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Allocate memory for the thread info structure */
|
/* Allocate memory for the thread info structure */
|
||||||
thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
|
thread = (SDL_Thread *) SDL_calloc(1, sizeof(*thread));
|
||||||
if (thread == NULL) {
|
if (thread == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
return (NULL);
|
return NULL;
|
||||||
}
|
}
|
||||||
SDL_zerop(thread);
|
|
||||||
thread->status = -1;
|
thread->status = -1;
|
||||||
SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
|
SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
|
||||||
|
|
||||||
|
@ -344,57 +329,29 @@ SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
|
||||||
if (thread->name == NULL) {
|
if (thread->name == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
SDL_free(thread);
|
SDL_free(thread);
|
||||||
return (NULL);
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the arguments for the thread */
|
thread->userfunc = fn;
|
||||||
args = (thread_args *) SDL_malloc(sizeof(*args));
|
thread->userdata = data;
|
||||||
if (args == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
if (thread->name) {
|
|
||||||
SDL_free(thread->name);
|
|
||||||
}
|
|
||||||
SDL_free(thread);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
args->func = fn;
|
|
||||||
args->data = data;
|
|
||||||
args->info = thread;
|
|
||||||
args->wait = SDL_CreateSemaphore(0);
|
|
||||||
if (args->wait == NULL) {
|
|
||||||
if (thread->name) {
|
|
||||||
SDL_free(thread->name);
|
|
||||||
}
|
|
||||||
SDL_free(thread);
|
|
||||||
SDL_free(args);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->stacksize = stacksize;
|
thread->stacksize = stacksize;
|
||||||
|
|
||||||
/* Create the thread and go! */
|
/* Create the thread and go! */
|
||||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||||
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
|
ret = SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread);
|
||||||
#else
|
#else
|
||||||
ret = SDL_SYS_CreateThread(thread, args);
|
ret = SDL_SYS_CreateThread(thread);
|
||||||
#endif
|
#endif
|
||||||
if (ret >= 0) {
|
if (ret < 0) {
|
||||||
/* Wait for the thread function to use arguments */
|
|
||||||
SDL_SemWait(args->wait);
|
|
||||||
} else {
|
|
||||||
/* Oops, failed. Gotta free everything */
|
/* Oops, failed. Gotta free everything */
|
||||||
if (thread->name) {
|
SDL_free(thread->name);
|
||||||
SDL_free(thread->name);
|
|
||||||
}
|
|
||||||
SDL_free(thread);
|
SDL_free(thread);
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
}
|
}
|
||||||
SDL_DestroySemaphore(args->wait);
|
|
||||||
SDL_free(args);
|
|
||||||
|
|
||||||
/* Everything is running now */
|
/* Everything is running now */
|
||||||
return (thread);
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||||
|
|
|
@ -60,11 +60,14 @@ struct SDL_Thread
|
||||||
SDL_error errbuf;
|
SDL_error errbuf;
|
||||||
char *name;
|
char *name;
|
||||||
size_t stacksize; /* 0 for default, >0 for user-specified stack size. */
|
size_t stacksize; /* 0 for default, >0 for user-specified stack size. */
|
||||||
|
int (SDLCALL * userfunc) (void *);
|
||||||
|
void *userdata;
|
||||||
void *data;
|
void *data;
|
||||||
|
void *endfunc; /* only used on some platforms. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the function called to run a thread */
|
/* This is the function called to run a thread */
|
||||||
extern void SDL_RunThread(void *data);
|
extern void SDL_RunThread(SDL_Thread *thread);
|
||||||
|
|
||||||
/* This is the system-independent thread local storage structure */
|
/* This is the system-independent thread local storage structure */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
|
|
||||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
|
SDL_SYS_CreateThread(SDL_Thread * thread,
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread,
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
pfnSDL_CurrentEndThread pfnEndThread)
|
pfnSDL_CurrentEndThread pfnEndThread)
|
||||||
#else
|
#else
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
SDL_SYS_CreateThread(SDL_Thread * thread)
|
||||||
#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
||||||
{
|
{
|
||||||
return SDL_SetError("Threads are not supported on this platform");
|
return SDL_SetError("Threads are not supported on this platform");
|
||||||
|
|
|
@ -37,11 +37,11 @@
|
||||||
|
|
||||||
static int ThreadEntry(SceSize args, void *argp)
|
static int ThreadEntry(SceSize args, void *argp)
|
||||||
{
|
{
|
||||||
SDL_RunThread(*(void **) argp);
|
SDL_RunThread(*(SDL_Thread **) argp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
|
int SDL_SYS_CreateThread(SDL_Thread *thread)
|
||||||
{
|
{
|
||||||
SceKernelThreadInfo status;
|
SceKernelThreadInfo status;
|
||||||
int priority = 32;
|
int priority = 32;
|
||||||
|
@ -59,7 +59,7 @@ int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
|
||||||
return SDL_SetError("sceKernelCreateThread() failed");
|
return SDL_SetError("sceKernelCreateThread() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
sceKernelStartThread(thread->handle, 4, &args);
|
sceKernelStartThread(thread->handle, 4, &thread);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ RunThread(void *data)
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
Android_JNI_SetupThread();
|
Android_JNI_SetupThread();
|
||||||
#endif
|
#endif
|
||||||
SDL_RunThread(data);
|
SDL_RunThread((SDL_Thread *) data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ static SDL_bool checked_setname = SDL_FALSE;
|
||||||
static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
|
static int (*ppthread_setname_np)(pthread_t, const char*) = NULL;
|
||||||
#endif
|
#endif
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
SDL_SYS_CreateThread(SDL_Thread * thread)
|
||||||
{
|
{
|
||||||
pthread_attr_t type;
|
pthread_attr_t type;
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the thread and go! */
|
/* Create the thread and go! */
|
||||||
if (pthread_create(&thread->handle, &type, RunThread, args) != 0) {
|
if (pthread_create(&thread->handle, &type, RunThread, thread) != 0) {
|
||||||
return SDL_SetError("Not enough resources to create thread");
|
return SDL_SetError("Not enough resources to create thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,16 +40,16 @@ extern "C" {
|
||||||
static void
|
static void
|
||||||
RunThread(void *args)
|
RunThread(void *args)
|
||||||
{
|
{
|
||||||
SDL_RunThread(args);
|
SDL_RunThread((SDL_Thread *) args);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
SDL_SYS_CreateThread(SDL_Thread * thread)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// !!! FIXME: no way to set a thread stack size here.
|
// !!! FIXME: no way to set a thread stack size here.
|
||||||
std::thread cpp_thread(RunThread, args);
|
std::thread cpp_thread(RunThread, thread);
|
||||||
thread->handle = (void *) new std::thread(std::move(cpp_thread));
|
thread->handle = (void *) new std::thread(std::move(cpp_thread));
|
||||||
return 0;
|
return 0;
|
||||||
} catch (std::system_error & ex) {
|
} catch (std::system_error & ex) {
|
||||||
|
|
|
@ -74,23 +74,16 @@ typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
|
||||||
#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
||||||
|
|
||||||
|
|
||||||
typedef struct ThreadStartParms
|
|
||||||
{
|
|
||||||
void *args;
|
|
||||||
pfnSDL_CurrentEndThread pfnCurrentEndThread;
|
|
||||||
} tThreadStartParms, *pThreadStartParms;
|
|
||||||
|
|
||||||
static DWORD
|
static DWORD
|
||||||
RunThread(void *data)
|
RunThread(void *data)
|
||||||
{
|
{
|
||||||
pThreadStartParms pThreadParms = (pThreadStartParms) data;
|
SDL_Thread *thread = (SDL_Thread *) data;
|
||||||
pfnSDL_CurrentEndThread pfnEndThread = pThreadParms->pfnCurrentEndThread;
|
pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread) thread->endfunc;
|
||||||
void *args = pThreadParms->args;
|
SDL_RunThread(thread);
|
||||||
SDL_free(pThreadParms);
|
if (pfnEndThread != NULL) {
|
||||||
SDL_RunThread(args);
|
|
||||||
if (pfnEndThread != NULL)
|
|
||||||
pfnEndThread(0);
|
pfnEndThread(0);
|
||||||
return (0);
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI
|
static DWORD WINAPI
|
||||||
|
@ -107,33 +100,27 @@ RunThreadViaBeginThreadEx(void *data)
|
||||||
|
|
||||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args,
|
SDL_SYS_CreateThread(SDL_Thread * thread,
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread,
|
pfnSDL_CurrentBeginThread pfnBeginThread,
|
||||||
pfnSDL_CurrentEndThread pfnEndThread)
|
pfnSDL_CurrentEndThread pfnEndThread)
|
||||||
{
|
{
|
||||||
#elif defined(__CYGWIN__) || defined(__WINRT__)
|
#elif defined(__CYGWIN__) || defined(__WINRT__)
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
SDL_SYS_CreateThread(SDL_Thread * thread)
|
||||||
{
|
{
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
|
pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
|
||||||
pfnSDL_CurrentEndThread pfnEndThread = NULL;
|
pfnSDL_CurrentEndThread pfnEndThread = NULL;
|
||||||
#else
|
#else
|
||||||
int
|
int
|
||||||
SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
SDL_SYS_CreateThread(SDL_Thread * thread)
|
||||||
{
|
{
|
||||||
pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
|
pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
|
||||||
pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
|
pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
|
||||||
#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
|
||||||
pThreadStartParms pThreadParms =
|
|
||||||
(pThreadStartParms) SDL_malloc(sizeof(tThreadStartParms));
|
|
||||||
const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
|
const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
|
||||||
if (!pThreadParms) {
|
|
||||||
return SDL_OutOfMemory();
|
|
||||||
}
|
|
||||||
/* Save the function which we will have to call to clear the RTL of calling app! */
|
/* Save the function which we will have to call to clear the RTL of calling app! */
|
||||||
pThreadParms->pfnCurrentEndThread = pfnEndThread;
|
thread->endfunc = pfnEndThread;
|
||||||
/* Also save the real parameters we have to pass to thread function */
|
|
||||||
pThreadParms->args = args;
|
|
||||||
|
|
||||||
/* thread->stacksize == 0 means "system default", same as win32 expects */
|
/* thread->stacksize == 0 means "system default", same as win32 expects */
|
||||||
if (pfnBeginThread) {
|
if (pfnBeginThread) {
|
||||||
|
@ -141,12 +128,12 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
|
||||||
thread->handle = (SYS_ThreadHandle)
|
thread->handle = (SYS_ThreadHandle)
|
||||||
((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize,
|
((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize,
|
||||||
RunThreadViaBeginThreadEx,
|
RunThreadViaBeginThreadEx,
|
||||||
pThreadParms, flags, &threadid));
|
thread, flags, &threadid));
|
||||||
} else {
|
} else {
|
||||||
DWORD threadid = 0;
|
DWORD threadid = 0;
|
||||||
thread->handle = CreateThread(NULL, thread->stacksize,
|
thread->handle = CreateThread(NULL, thread->stacksize,
|
||||||
RunThreadViaCreateThread,
|
RunThreadViaCreateThread,
|
||||||
pThreadParms, flags, &threadid);
|
thread, flags, &threadid);
|
||||||
}
|
}
|
||||||
if (thread->handle == NULL) {
|
if (thread->handle == NULL) {
|
||||||
return SDL_SetError("Not enough resources to create thread");
|
return SDL_SetError("Not enough resources to create thread");
|
||||||
|
|
Loading…
Reference in New Issue