thread: Reworked SDL_CreateThread to be consistent across platforms.

Also documented missing and weird bits, rename typedefs to fit SDL standards.
This commit is contained in:
Ryan C. Gordon 2024-05-21 01:46:48 -04:00
parent 983544a53e
commit 0ec716819e
30 changed files with 214 additions and 219 deletions

View file

@ -1630,6 +1630,8 @@ becomes:
## SDL_thread.h ## SDL_thread.h
SDL_CreateThread and SDL_CreateThreadWithStackSpace now take beginthread/endthread function pointers on all platforms (ignoring them on most), and have been replaced with macros that hide this detail on all platforms. This works the same as before at the source code level, but the actual function signature that is called in SDL has changed. The library's exported symbol is SDL_CreateThreadRuntime, and looking for "SDL_CreateThread" in the DLL/Shared Library/Dylib will fail. You should not call this directly, but instead always use the macro!
The following functions have been renamed: The following functions have been renamed:
* SDL_TLSCleanup() => SDL_CleanupTLS() * SDL_TLSCleanup() => SDL_CleanupTLS()
* SDL_TLSCreate() => SDL_CreateTLS() * SDL_TLSCreate() => SDL_CreateTLS()

View file

@ -45,14 +45,44 @@
extern "C" { extern "C" {
#endif #endif
/* The SDL thread structure, defined in SDL_thread.c */ /**
struct SDL_Thread; * The SDL thread object.
*
* These are opaque data.
*
* \since This datatype is available since SDL 3.0.0.
*
* \sa SDL_CreateThread
* \sa SDL_WaitThread
*/
typedef struct SDL_Thread SDL_Thread; typedef struct SDL_Thread SDL_Thread;
/* The SDL thread ID */ /**
* A unique numeric ID that identifies a thread.
*
* These are different that SDL_Thread objects, which are generally what an
* application will operate on, but having a way to uniquely identify a
* thread can be useful at times.
*
* \since This datatype is available since SDL 3.0.0.
*
* \sa SDL_GetThreadID
* \sa SDL_GetCurrentThreadID
*/
typedef Uint64 SDL_ThreadID; typedef Uint64 SDL_ThreadID;
/* Thread local storage ID, 0 is the invalid ID */ /**
* Thread local storage ID values.
*
* 0 is the invalid ID. An app can create these and then set data for
* these IDs that is unique to each thread.
*
* \since This datatype is available since SDL 3.0.0.
*
* \sa SDL_CreateTLS
* \sa SDL_GetTLS
* \sa SDL_SetTLS
*/
typedef Uint32 SDL_TLSID; typedef Uint32 SDL_TLSID;
/** /**
@ -74,7 +104,7 @@ typedef enum SDL_ThreadPriority {
} SDL_ThreadPriority; } SDL_ThreadPriority;
/** /**
* The function passed to SDL_CreateThread(). * The function passed to SDL_CreateThread() as the new thread's entry point.
* *
* \param data what was passed as `data` to SDL_CreateThread() * \param data what was passed as `data` to SDL_CreateThread()
* \returns a value that can be reported through SDL_WaitThread(). * \returns a value that can be reported through SDL_WaitThread().
@ -83,91 +113,86 @@ typedef enum SDL_ThreadPriority {
*/ */
typedef int (SDLCALL * SDL_ThreadFunction) (void *data); typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
/*
* We compile SDL into a DLL. This means, that it's the DLL which
* creates a new thread for the calling process with the SDL_CreateThread()
* API. There is a problem with this, that only the RTL of the SDL3.DLL will
* be initialized for those threads, and not the RTL of the calling
* application!
*
* To solve this, we make a little hack here.
*
* We'll always use the caller's _beginthread() and _endthread() APIs to
* start a new thread. This way, if it's the SDL3.DLL which uses this API,
* then the RTL of SDL3.DLL will be used to create the new thread, and if it's
* the application, then the RTL of the application will be used.
*
* So, in short:
* Always use the _beginthread() and _endthread() of the calling runtime
* library!
*/
#if (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)) && !defined(SDL_PLATFORM_WINRT) #if (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)) && !defined(SDL_PLATFORM_WINRT)
#define SDL_PASSED_BEGINTHREAD_ENDTHREAD
typedef uintptr_t (__cdecl * pfnSDL_CurrentBeginThread) #ifndef SDL_BeginThreadFunction
(void *, unsigned, unsigned (__stdcall *func)(void *), /**
void * /*arg*/, unsigned, unsigned * /* threadID */); * Macro that manages the compiler's `_beginthreadex` implementation.
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
#ifndef SDL_beginthread
#define SDL_beginthread _beginthreadex
#endif
#ifndef SDL_endthread
#define SDL_endthread _endthreadex
#endif
/*
* Create a SDL Thread
* *
* \param fn Thread function * On Windows (and maybe other platforms), a program might use a different
* \param name name * C runtime than its libraries. Or, in SDL's case, it might use a C runtime
* \param data some data * while SDL uses none at all.
* \param pfnBeginThread begin function
* \param pfnEndThread end function
* *
* \returns SDL_Thread pointer * C runtimes expect to initialize thread-specific details when a new thread
* is created, but to do this in SDL_CreateThread would require SDL to know
* intimate details about the caller's C runtime, which is not possible.
* *
* \since This function is available since SDL 3.0.0. * So SDL_CreateThread has two extra parameters, which are
* hidden at compile time by macros: the C runtime's `_beginthreadex` and
* `_endthreadex` entry points. If these are not NULL, they are used to spin
* and terminate the new thread; otherwise the standard Win32 `CreateThread`
* function is used. When `SDL_CreateThread` is called from a compiler that
* needs this C runtime thread init function, macros insert the appropriate
* function pointers for SDL_CreateThread's caller (which might be a different
* compiler with a different runtime in different calls to SDL_CreateThread!).
*
* This defaults to `_beginthreadex` on Windows (and NULL everywhere else),
* but apps that have extremely specific special needs can define this to
* something else and the SDL headers will use it, passing the app-defined
* value to SDL_CreateThread calls. Redefine this with caution!
*
* Unless you are doing something extremely complicated, like perhaps a
* language binding, **you should never reference this directly**. Let SDL's
* macros handle this platform-specific detail transparently!
*
* \threadsafety It is safe to call this macro from any thread.
*
* \since This macro is available since SDL 3.0.0.
*
* \sa SDL_CreateThread
*/ */
extern SDL_DECLSPEC SDL_Thread *SDLCALL #define SDL_BeginThreadFunction _beginthreadex
SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
pfnSDL_CurrentBeginThread pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread);
/*
* Create a SDL Thread, with explicit stack size
*
* \param fn Thread function
* \param name name
* \param stacksize stack size
* \param data some data
* \param pfnBeginThread begin function
* \param pfnEndThread end function
*
* \returns SDL_Thread pointer
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC SDL_Thread *SDLCALL
SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn,
const char *name, const size_t stacksize, void *data,
pfnSDL_CurrentBeginThread pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread);
#if !defined(__BUILDING_SDL2_COMPAT__) /* do not conflict with sdl2-compat::sdl3_include_wrapper.h */
#if defined(SDL_CreateThread) && SDL_DYNAMIC_API
#undef SDL_CreateThread
#define SDL_CreateThread(fn, name, data) SDL_CreateThread_REAL(fn, name, data, (pfnSDL_CurrentBeginThread)SDL_beginthread, (pfnSDL_CurrentEndThread)SDL_endthread)
#undef SDL_CreateThreadWithStackSize
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize_REAL(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)SDL_beginthread, (pfnSDL_CurrentEndThread)SDL_endthread)
#else
#define SDL_CreateThread(fn, name, data) SDL_CreateThread(fn, name, data, (pfnSDL_CurrentBeginThread)SDL_beginthread, (pfnSDL_CurrentEndThread)SDL_endthread)
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSize(fn, name, stacksize, data, (pfnSDL_CurrentBeginThread)SDL_beginthread, (pfnSDL_CurrentEndThread)SDL_endthread)
#endif #endif
#endif /* !__BUILDING_SDL2_COMPAT__ */
#else #ifndef SDL_EndThreadFunction
/**
* Macro that manages the compiler's `_endthreadex` implementation.
*
* Please see the detailed explanation in SDL_BeginThreadFunction.
*
* This defaults to `_endthreadex` on Windows (and NULL everywhere else),
* but apps that have extremely specific special needs can define this to
* something else and the SDL headers will use it, passing the app-defined
* value to SDL_CreateThread calls. Redefine this with caution!
*
* Unless you are doing something extremely complicated, like perhaps a
* language binding, **you should never reference this directly**. Let SDL's
* macros handle this platform-specific detail transparently!
*
* \threadsafety It is safe to call this macro from any thread.
*
* \since This macro is available since SDL 3.0.0.
*
* \sa SDL_CreateThread
*/
#define SDL_EndThreadFunction _endthreadex
#endif
#endif
/* currently no other platforms than Windows use _beginthreadex/_endthreadex things. */
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
#ifndef SDL_BeginThreadFunction
#define SDL_BeginThreadFunction NULL
#endif
#ifndef SDL_EndThreadFunction
#define SDL_EndThreadFunction NULL
#endif
#endif
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
/* Note that this isn't the correct function signature, but this is what the API reference manual should look like for all intents and purposes. */
/** /**
* Create a new thread with a default stack size. * Create a new thread with a default stack size.
@ -178,6 +203,16 @@ SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn,
* SDL_CreateThreadWithStackSize(fn, name, 0, data); * SDL_CreateThreadWithStackSize(fn, name, 0, data);
* ``` * ```
* *
* Note that this "function" is actually a macro that calls an internal
* function with two extra parameters not listed here; they are
* hidden through preprocessor macros and are needed to support various C
* runtimes at the point of the function call. Language bindings that aren't
* using the C headers will need to deal with this.
*
* Usually, apps should just call this function the same way on every platform and
* let the macros hide the details. See SDL_BeginThreadFunction for the
* technical details.
*
* \param fn the SDL_ThreadFunction function to call in the new thread * \param fn the SDL_ThreadFunction function to call in the new thread
* \param name the name of the thread * \param name the name of the thread
* \param data a pointer that is passed to `fn` * \param data a pointer that is passed to `fn`
@ -219,6 +254,21 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(SDL_ThreadFunction fn,
* multiple of the system's page size (in many cases, this is 4 kilobytes, but * multiple of the system's page size (in many cases, this is 4 kilobytes, but
* check your system documentation). * check your system documentation).
* *
* Note that this "function" is actually a macro that calls an internal
* function with two extra parameters not listed here; they are
* hidden through preprocessor macros and are needed to support various C
* runtimes at the point of the function call. Language bindings that aren't
* using the C headers will need to deal with this.
*
* The actual symbol in SDL's library is `SDL_CreateThreadRuntime` (or
* `SDL_CreateThreadWithStackSpaceRuntime`), so there is no symbol clash, but
* trying to load an SDL shared library and look for "SDL_CreateThread"
* will fail.
*
* Usually, apps should just call this function the same way on every platform and
* let the macros hide the details. See SDL_BeginThreadFunction for the
* technical details.
*
* \param fn the SDL_ThreadFunction function to call in the new thread * \param fn the SDL_ThreadFunction function to call in the new thread
* \param name the name of the thread * \param name the name of the thread
* \param stacksize the size, in bytes, to allocate for the new thread stack. * \param stacksize the size, in bytes, to allocate for the new thread stack.
@ -233,7 +283,14 @@ extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(SDL_ThreadFunction fn,
* \sa SDL_WaitThread * \sa SDL_WaitThread
*/ */
extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data); extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data);
#endif
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
/* These are the actual functions exported from SDL! Don't use them directly! Use the SDL_CreateThread and SDL_CreateThreadWithStackSize macros! */
extern SDL_DECLSPEC SDL_Thread *SDLCALL SDL_CreateThreadRuntime(SDL_ThreadFunction fn, const char *name, void *data, SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread);
extern SDL_DECLSPEC SDL_Thread *SDLCALL SDL_CreateThreadWithStackSizeRuntime(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data,SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread);
#define SDL_CreateThread(fn, name, data) SDL_CreateThreadRuntime(fn, name, data, (SDL_FunctionPointer) (SDL_BeginThreadFunction), (SDL_FunctionPointer) (SDL_EndThreadFunction))
#define SDL_CreateThreadWithStackSize(fn, name, stacksize, data) SDL_CreateThreadWithStackSizeRuntime(fn, name, stacksize, data, (SDL_FunctionPointer) (SDL_BeginThreadFunction), (SDL_FunctionPointer) (SDL_EndThreadFunction))
#endif #endif
/** /**

View file

@ -1633,10 +1633,9 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
// Start the audio thread if necessary // Start the audio thread if necessary
if (!current_audio.impl.ProvidesOwnCallbackThread) { if (!current_audio.impl.ProvidesOwnCallbackThread) {
const size_t stacksize = 0; // just take the system default, since audio streams might have callbacks.
char threadname[64]; char threadname[64];
SDL_GetAudioThreadName(device, threadname, sizeof (threadname)); SDL_GetAudioThreadName(device, threadname, sizeof (threadname));
device->thread = SDL_CreateThreadInternal(device->iscapture ? CaptureAudioThread : OutputAudioThread, threadname, stacksize, device); device->thread = SDL_CreateThread(device->iscapture ? CaptureAudioThread : OutputAudioThread, threadname, device);
if (!device->thread) { if (!device->thread) {
ClosePhysicalAudioDevice(device); ClosePhysicalAudioDevice(device);

View file

@ -952,7 +952,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
char threadname[64]; char threadname[64];
SDL_GetAudioThreadName(device, threadname, sizeof(threadname)); SDL_GetAudioThreadName(device, threadname, sizeof(threadname));
device->hidden->thread = SDL_CreateThreadInternal(AudioQueueThreadEntry, threadname, 0, device); device->hidden->thread = SDL_CreateThread(AudioQueueThreadEntry, threadname, device);
if (!device->hidden->thread) { if (!device->hidden->thread) {
return -1; return -1;
} }

View file

@ -978,7 +978,7 @@ static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_Audio
// ok, we have a sane list, let's set up hotplug notifications now... // ok, we have a sane list, let's set up hotplug notifications now...
SDL_AtomicSet(&pulseaudio_hotplug_thread_active, 1); SDL_AtomicSet(&pulseaudio_hotplug_thread_active, 1);
pulseaudio_hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, ready_sem); // !!! FIXME: this can probably survive in significantly less stack space. pulseaudio_hotplug_thread = SDL_CreateThreadWithStackSize(HotplugThread, "PulseHotplug", 256 * 1024, ready_sem); // !!! FIXME: this can probably survive in significantly less stack space.
SDL_WaitSemaphore(ready_sem); SDL_WaitSemaphore(ready_sem);
SDL_DestroySemaphore(ready_sem); SDL_DestroySemaphore(ready_sem);
} }

View file

@ -210,7 +210,7 @@ static int InitManagementThread(void)
SDL_AtomicSetPtr((void **) &ManagementThreadPendingTasks, NULL); SDL_AtomicSetPtr((void **) &ManagementThreadPendingTasks, NULL);
SDL_AtomicSet(&ManagementThreadShutdown, 0); SDL_AtomicSet(&ManagementThreadShutdown, 0);
ManagementThread = SDL_CreateThreadInternal(ManagementThreadEntry, "SDLWASAPIMgmt", 256 * 1024, &mgmtdata); // !!! FIXME: maybe even smaller stack size? ManagementThread = SDL_CreateThreadWithStackSize(ManagementThreadEntry, "SDLWASAPIMgmt", 256 * 1024, &mgmtdata); // !!! FIXME: maybe even smaller stack size?
if (!ManagementThread) { if (!ManagementThread) {
return -1; return -1;
} }

View file

@ -1150,7 +1150,7 @@ SDL_Camera *SDL_OpenCameraDevice(SDL_CameraDeviceID instance_id, const SDL_Camer
if (!camera_driver.impl.ProvidesOwnCallbackThread) { if (!camera_driver.impl.ProvidesOwnCallbackThread) {
char threadname[64]; char threadname[64];
SDL_GetCameraThreadName(device, threadname, sizeof (threadname)); SDL_GetCameraThreadName(device, threadname, sizeof (threadname));
device->thread = SDL_CreateThreadInternal(CameraThread, threadname, 0, device); device->thread = SDL_CreateThread(CameraThread, threadname, device);
if (!device->thread) { if (!device->thread) {
ClosePhysicalCameraDevice(device); ClosePhysicalCameraDevice(device);
ReleaseCameraDevice(device); ReleaseCameraDevice(device);

View file

@ -107,7 +107,7 @@ static int StartBeApp(void *unused)
static int StartBeLooper() static int StartBeLooper()
{ {
if (!be_app) { if (!be_app) {
SDL_AppThread = SDL_CreateThreadInternal(StartBeApp, "SDLApplication", 0, NULL); SDL_AppThread = SDL_CreateThread(StartBeApp, "SDLApplication", NULL);
if (!SDL_AppThread) { if (!SDL_AppThread) {
return SDL_SetError("Couldn't create BApplication thread"); return SDL_SetError("Couldn't create BApplication thread");
} }

View file

@ -459,7 +459,7 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
args->callback = callback; args->callback = callback;
args->userdata = userdata; args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_file_dialog_thread, "SDL_ShowOpenFileDialog", 0, (void *) args); thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_ShowOpenFileDialog", (void *) args);
if (thread == NULL) { if (thread == NULL) {
callback(userdata, NULL, -1); callback(userdata, NULL, -1);
@ -495,7 +495,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
args->callback = callback; args->callback = callback;
args->userdata = userdata; args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_file_dialog_thread, "SDL_ShowSaveFileDialog", 0, (void *) args); thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_ShowSaveFileDialog", (void *) args);
if (thread == NULL) { if (thread == NULL) {
callback(userdata, NULL, -1); callback(userdata, NULL, -1);
@ -528,7 +528,7 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S
args->default_folder = default_location; args->default_folder = default_location;
args->userdata = userdata; args->userdata = userdata;
thread = SDL_CreateThreadInternal(windows_folder_dialog_thread, "SDL_ShowOpenFolderDialog", 0, (void *) args); thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_ShowOpenFolderDialog", (void *) args);
if (thread == NULL) { if (thread == NULL) {
callback(userdata, NULL, -1); callback(userdata, NULL, -1);

View file

@ -84,8 +84,8 @@ SDL3_0.0.0 {
SDL_CreateTexture; SDL_CreateTexture;
SDL_CreateTextureFromSurface; SDL_CreateTextureFromSurface;
SDL_CreateTextureWithProperties; SDL_CreateTextureWithProperties;
SDL_CreateThread; SDL_CreateThreadRuntime;
SDL_CreateThreadWithStackSize; SDL_CreateThreadWithStackSizeRuntime;
SDL_CreateWindow; SDL_CreateWindow;
SDL_CreateWindowAndRenderer; SDL_CreateWindowAndRenderer;
SDL_CreateWindowWithProperties; SDL_CreateWindowWithProperties;

View file

@ -109,8 +109,8 @@
#define SDL_CreateTexture SDL_CreateTexture_REAL #define SDL_CreateTexture SDL_CreateTexture_REAL
#define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL #define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL
#define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL #define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL
#define SDL_CreateThread SDL_CreateThread_REAL #define SDL_CreateThreadRuntime SDL_CreateThreadRuntime_REAL
#define SDL_CreateThreadWithStackSize SDL_CreateThreadWithStackSize_REAL #define SDL_CreateThreadWithStackSizeRuntime SDL_CreateThreadWithStackSizeRuntime_REAL
#define SDL_CreateWindow SDL_CreateWindow_REAL #define SDL_CreateWindow SDL_CreateWindow_REAL
#define SDL_CreateWindowAndRenderer SDL_CreateWindowAndRenderer_REAL #define SDL_CreateWindowAndRenderer SDL_CreateWindowAndRenderer_REAL
#define SDL_CreateWindowWithProperties SDL_CreateWindowWithProperties_REAL #define SDL_CreateWindowWithProperties SDL_CreateWindowWithProperties_REAL

View file

@ -46,26 +46,6 @@ SDL_DYNAPI_PROC(int,SDL_sscanf,(const char *a, SDL_SCANF_FORMAT_STRING const cha
SDL_DYNAPI_PROC(int,SDL_swprintf,(SDL_OUT_Z_CAP(b) wchar_t *a, size_t b, SDL_PRINTF_FORMAT_STRING const wchar_t *c, ...),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_swprintf,(SDL_OUT_Z_CAP(b) wchar_t *a, size_t b, SDL_PRINTF_FORMAT_STRING const wchar_t *c, ...),(a,b,c),return)
#endif #endif
#ifdef SDL_CreateThread
#undef SDL_CreateThread
#endif
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char *b, void *c, pfnSDL_CurrentBeginThread d, pfnSDL_CurrentEndThread e),(a,b,c,d,e),return)
#else
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char *b, void *c),(a,b,c),return)
#endif
#ifdef SDL_CreateThreadWithStackSize
#undef SDL_CreateThreadWithStackSize
#endif
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThreadWithStackSize,(SDL_ThreadFunction a, const char *b, const size_t c, void *d, pfnSDL_CurrentBeginThread e, pfnSDL_CurrentEndThread f),(a,b,c,d,e,f),return)
#else
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThreadWithStackSize,(SDL_ThreadFunction a, const char *b, const size_t c, void *d),(a,b,c,d),return)
#endif
/* New API symbols are added at the end */ /* New API symbols are added at the end */
SDL_DYNAPI_PROC(SDL_Surface*,SDL_AcquireCameraFrame,(SDL_Camera *a, Uint64 *b),(a,b),return) SDL_DYNAPI_PROC(SDL_Surface*,SDL_AcquireCameraFrame,(SDL_Camera *a, Uint64 *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),return)
@ -149,6 +129,8 @@ SDL_DYNAPI_PROC(SDL_TLSID,SDL_CreateTLS,(void),(),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTexture,(SDL_Renderer *a, SDL_PixelFormatEnum b, int c, int d, int e),(a,b,c,d,e),return) SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTexture,(SDL_Renderer *a, SDL_PixelFormatEnum b, int c, int d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureFromSurface,(SDL_Renderer *a, SDL_Surface *b),(a,b),return) SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureFromSurface,(SDL_Renderer *a, SDL_Surface *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureWithProperties,(SDL_Renderer *a, SDL_PropertiesID b),(a,b),return) SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureWithProperties,(SDL_Renderer *a, SDL_PropertiesID b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThreadRuntime,(SDL_ThreadFunction a, const char *b, void *c, SDL_FunctionPointer d, SDL_FunctionPointer e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThreadWithStackSizeRuntime,(SDL_ThreadFunction a, const char *b, const size_t c, void *d, SDL_FunctionPointer e, SDL_FunctionPointer f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindow,(const char *a, int b, int c, SDL_WindowFlags d),(a,b,c,d),return) SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindow,(const char *a, int b, int c, SDL_WindowFlags d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_CreateWindowAndRenderer,(const char *a, int b, int c, SDL_WindowFlags d, SDL_Window **e, SDL_Renderer **f),(a,b,c,d,e,f),return) SDL_DYNAPI_PROC(int,SDL_CreateWindowAndRenderer,(const char *a, int b, int c, SDL_WindowFlags d, SDL_Window **e, SDL_Renderer **f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithProperties,(SDL_PropertiesID a),(a),return) SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithProperties,(SDL_PropertiesID a),(a),return)

View file

@ -179,7 +179,7 @@ static void hidapi_thread_create(hidapi_thread_state *state, void *(*func)(void*
*/ */
param->func = func; param->func = func;
param->func_arg = func_arg; param->func_arg = func_arg;
state->thread = SDL_CreateThreadInternal(RunInputThread, "libusb", 0, param); state->thread = SDL_CreateThread(RunInputThread, "libusb", param);
} }
static void hidapi_thread_join(hidapi_thread_state *state) static void hidapi_thread_join(hidapi_thread_state *state)

View file

@ -156,7 +156,7 @@ static int SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
} }
SDL_AtomicSet(&ctx->running, SDL_TRUE); SDL_AtomicSet(&ctx->running, SDL_TRUE);
ctx->thread = SDL_CreateThreadInternal(SDL_HIDAPI_RumbleThread, "HIDAPI Rumble", 0, ctx); ctx->thread = SDL_CreateThread(SDL_HIDAPI_RumbleThread, "HIDAPI Rumble", ctx);
if (!ctx->thread) { if (!ctx->thread) {
SDL_HIDAPI_StopRumbleThread(ctx); SDL_HIDAPI_StopRumbleThread(ctx);
return -1; return -1;

View file

@ -286,7 +286,7 @@ static int SDL_StartJoystickThread(void)
} }
s_bJoystickThreadQuit = SDL_FALSE; s_bJoystickThreadQuit = SDL_FALSE;
s_joystickThread = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL); s_joystickThread = SDL_CreateThreadWithStackSize(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
if (!s_joystickThread) { if (!s_joystickThread) {
return -1; return -1;
} }

View file

@ -120,7 +120,7 @@ static int SDL_ANDROID_StartSensorThread(SDL_AndroidSensorThreadContext *ctx)
} }
SDL_AtomicSet(&ctx->running, SDL_TRUE); SDL_AtomicSet(&ctx->running, SDL_TRUE);
ctx->thread = SDL_CreateThreadInternal(SDL_ANDROID_SensorThread, "Sensors", 0, ctx); ctx->thread = SDL_CreateThread(SDL_ANDROID_SensorThread, "Sensors", ctx);
if (!ctx->thread) { if (!ctx->thread) {
SDL_ANDROID_StopSensorThread(ctx); SDL_ANDROID_StopSensorThread(ctx);
return -1; return -1;

View file

@ -36,13 +36,9 @@ extern "C" {
saves a system-dependent thread id in thread->id, and returns 0 saves a system-dependent thread id in thread->id, and returns 0
on success. on success.
*/ */
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
extern int SDL_SYS_CreateThread(SDL_Thread *thread, extern int SDL_SYS_CreateThread(SDL_Thread *thread,
pfnSDL_CurrentBeginThread pfnBeginThread, SDL_FunctionPointer pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread); SDL_FunctionPointer pfnEndThread);
#else
extern int SDL_SYS_CreateThread(SDL_Thread *thread);
#endif
/* This function does any necessary setup in the child thread */ /* This function does any necessary setup in the child thread */
extern void SDL_SYS_SetupThread(const char *name); extern void SDL_SYS_SetupThread(const char *name);
@ -64,11 +60,6 @@ extern SDL_TLSData *SDL_SYS_GetTLSData(void);
/* Set the thread local storage for this thread */ /* Set the thread local storage for this thread */
extern int SDL_SYS_SetTLSData(SDL_TLSData *data); extern int SDL_SYS_SetTLSData(SDL_TLSData *data);
/* This is for internal SDL use, so we don't need #ifdefs everywhere. */
extern SDL_Thread *
SDL_CreateThreadInternal(int(SDLCALL *fn)(void *), const char *name,
const size_t stacksize, void *data);
/* Ends C function definitions when using C++ */ /* Ends C function definitions when using C++ */
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -307,28 +307,22 @@ void SDL_RunThread(SDL_Thread *thread)
} }
} }
#ifdef SDL_CreateThread SDL_Thread *SDL_CreateThreadWithStackSizeRuntime(SDL_ThreadFunction fn,
#undef SDL_CreateThread
#undef SDL_CreateThreadWithStackSize
#endif
#if SDL_DYNAMIC_API
#define SDL_CreateThread SDL_CreateThread_REAL
#define SDL_CreateThreadWithStackSize SDL_CreateThreadWithStackSize_REAL
#endif
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *),
const char *name, const size_t stacksize, void *data, const char *name, const size_t stacksize, void *data,
pfnSDL_CurrentBeginThread pfnBeginThread, SDL_FunctionPointer pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread) SDL_FunctionPointer pfnEndThread)
#else
SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *),
const char *name, const size_t stacksize, void *data)
#endif
{ {
SDL_Thread *thread; SDL_Thread *thread;
int ret; int ret;
// rather than check this in every backend, just make sure it's correct upfront. Only allow non-NULL if non-WinRT Windows, or Microsoft GDK.
#if (!defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)) || defined(SDL_PLATFORM_WINRT)
if (pfnBeginThread || pfnEndThread) {
SDL_SetError("_beginthreadex/_endthreadex not supported on this platform");
return NULL;
}
#endif
/* Allocate memory for the thread info structure */ /* Allocate memory for the thread info structure */
thread = (SDL_Thread *)SDL_calloc(1, sizeof(*thread)); thread = (SDL_Thread *)SDL_calloc(1, sizeof(*thread));
if (!thread) { if (!thread) {
@ -351,11 +345,7 @@ SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *),
thread->stacksize = stacksize; thread->stacksize = stacksize;
/* Create the thread and go! */ /* Create the thread and go! */
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
ret = SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread); ret = SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread);
#else
ret = SDL_SYS_CreateThread(thread);
#endif
if (ret < 0) { if (ret < 0) {
/* Oops, failed. Gotta free everything */ /* Oops, failed. Gotta free everything */
SDL_free(thread->name); SDL_free(thread->name);
@ -367,31 +357,12 @@ SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *),
return thread; return thread;
} }
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD SDL_Thread *SDL_CreateThreadRuntime(SDL_ThreadFunction fn,
SDL_Thread *SDLCALL SDL_CreateThread(int(SDLCALL *fn)(void *),
const char *name, void *data, const char *name, void *data,
pfnSDL_CurrentBeginThread pfnBeginThread, SDL_FunctionPointer pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread) SDL_FunctionPointer pfnEndThread)
#else
SDL_Thread *SDLCALL SDL_CreateThread(int(SDLCALL *fn)(void *),
const char *name, void *data)
#endif
{ {
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD return SDL_CreateThreadWithStackSizeRuntime(fn, name, 0, data, pfnBeginThread, pfnEndThread);
return SDL_CreateThreadWithStackSize(fn, name, 0, data, pfnBeginThread, pfnEndThread);
#else
return SDL_CreateThreadWithStackSize(fn, name, 0, data);
#endif
}
SDL_Thread *SDL_CreateThreadInternal(int(SDLCALL *fn)(void *), const char *name,
const size_t stacksize, void *data)
{
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, NULL, NULL);
#else
return SDL_CreateThreadWithStackSize(fn, name, stacksize, data);
#endif
} }
SDL_ThreadID SDL_GetThreadID(SDL_Thread *thread) SDL_ThreadID SDL_GetThreadID(SDL_Thread *thread)

View file

@ -24,13 +24,9 @@
#include "../SDL_systhread.h" #include "../SDL_systhread.h"
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
int SDL_SYS_CreateThread(SDL_Thread *thread, int SDL_SYS_CreateThread(SDL_Thread *thread,
pfnSDL_CurrentBeginThread pfnBeginThread, SDL_FunctionPointer pfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread) SDL_FunctionPointer pfnEndThread)
#else
int SDL_SYS_CreateThread(SDL_Thread *thread)
#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");
} }

View file

@ -42,11 +42,10 @@ static void ThreadEntry(void *arg)
threadExit(0); threadExit(0);
} }
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
#error "SDL_PASSED_BEGINTHREAD_ENDTHREAD is not supported on N3DS"
#endif
int SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
s32 priority = 0x30; s32 priority = 0x30;
int cpu = -1; int cpu = -1;

View file

@ -57,7 +57,9 @@ int CreateUnique(TInt (*aFunc)(const TDesC &aName, TAny *, TAny *), TAny *aPtr1,
return status; return status;
} }
int SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
RThread rthread; RThread rthread;

View file

@ -54,7 +54,9 @@ static int childThread(void *arg)
return res; return res;
} }
int SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
ee_thread_status_t status; ee_thread_status_t status;
ee_thread_t eethread; ee_thread_t eethread;

View file

@ -38,7 +38,9 @@ static int ThreadEntry(SceSize args, void *argp)
return 0; return 0;
} }
int SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
SceKernelThreadInfo status; SceKernelThreadInfo status;
int priority = 32; int priority = 32;

View file

@ -77,7 +77,9 @@ static int (*ppthread_setname_np)(const char *) = NULL;
static SDL_bool checked_setname = SDL_FALSE; 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 SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
pthread_attr_t type; pthread_attr_t type;

View file

@ -41,7 +41,9 @@ static void RunThread(void *args)
} }
extern "C" int extern "C" int
SDL_SYS_CreateThread(SDL_Thread *thread) SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
try { try {
// !!! FIXME: no way to set a thread stack size here. // !!! FIXME: no way to set a thread stack size here.

View file

@ -48,7 +48,10 @@ static int ThreadEntry(SceSize args, void *argp)
return 0; return 0;
} }
int SDL_SYS_CreateThread(SDL_Thread *thread) int SDL_SYS_CreateThread(SDL_Thread *thread,
SDL_FunctionPointer pfnBeginThread,
SDL_FunctionPointer pfnEndThread)
{ {
char thread_name[VITA_THREAD_NAME_MAX]; char thread_name[VITA_THREAD_NAME_MAX];
size_t stack_size = VITA_THREAD_STACK_SIZE_DEFAULT; size_t stack_size = VITA_THREAD_STACK_SIZE_DEFAULT;

View file

@ -32,20 +32,15 @@
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
#endif #endif
#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD typedef void (__cdecl * SDL_EndThreadExCallback) (unsigned retval);
/* We'll use the C library from this DLL */ typedef uintptr_t (__cdecl * SDL_BeginThreadExCallback)
#include <process.h> (void *security, unsigned stacksize, unsigned (__stdcall *startaddr)(void *),
typedef uintptr_t(__cdecl *pfnSDL_CurrentBeginThread)(void *, unsigned, void * arglist, unsigned initflag, unsigned *threadaddr);
unsigned(__stdcall *func)(void*),
void *arg, unsigned,
unsigned *threadID);
typedef void(__cdecl *pfnSDL_CurrentEndThread)(unsigned code);
#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
static DWORD RunThread(void *data) static DWORD RunThread(void *data)
{ {
SDL_Thread *thread = (SDL_Thread *)data; SDL_Thread *thread = (SDL_Thread *)data;
pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)thread->endfunc; SDL_EndThreadExCallback pfnEndThread = (SDL_EndThreadExCallback)thread->endfunc;
SDL_RunThread(thread); SDL_RunThread(thread);
if (pfnEndThread) { if (pfnEndThread) {
pfnEndThread(0); pfnEndThread(0);
@ -63,26 +58,16 @@ static unsigned __stdcall MINGW32_FORCEALIGN RunThreadViaBeginThreadEx(void *dat
return (unsigned)RunThread(data); return (unsigned)RunThread(data);
} }
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
int SDL_SYS_CreateThread(SDL_Thread *thread, int SDL_SYS_CreateThread(SDL_Thread *thread,
pfnSDL_CurrentBeginThread pfnBeginThread, SDL_FunctionPointer vpfnBeginThread,
pfnSDL_CurrentEndThread pfnEndThread) SDL_FunctionPointer vpfnEndThread)
{ {
#elif defined(SDL_PLATFORM_CYGWIN) || defined(SDL_PLATFORM_WINRT) SDL_BeginThreadExCallback pfnBeginThread = (SDL_BeginThreadExCallback) vpfnBeginThread;
int SDL_SYS_CreateThread(SDL_Thread *thread)
{
pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
pfnSDL_CurrentEndThread pfnEndThread = NULL;
#else
int SDL_SYS_CreateThread(SDL_Thread *thread)
{
pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex;
pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex;
#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0; const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0;
/* 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! */
thread->endfunc = (SDL_FunctionPointer)pfnEndThread; thread->endfunc = vpfnEndThread;
/* thread->stacksize == 0 means "system default", same as win32 expects */ /* thread->stacksize == 0 means "system default", same as win32 expects */
if (pfnBeginThread) { if (pfnBeginThread) {

View file

@ -221,7 +221,7 @@ int SDL_InitTimers(void)
SDL_AtomicSet(&data->active, 1); SDL_AtomicSet(&data->active, 1);
/* Timer threads use a callback into the app, so we can't set a limited stack size here. */ /* Timer threads use a callback into the app, so we can't set a limited stack size here. */
data->thread = SDL_CreateThreadInternal(SDL_TimerThread, name, 0, data); data->thread = SDL_CreateThread(SDL_TimerThread, name, data);
if (!data->thread) { if (!data->thread) {
SDL_QuitTimers(); SDL_QuitTimers();
return -1; return -1;

View file

@ -252,7 +252,7 @@ int PSP_EventInit(SDL_VideoDevice *_this)
return SDL_SetError("Can't create input semaphore"); return SDL_SetError("Can't create input semaphore");
} }
running = 1; running = 1;
if ((thread = SDL_CreateThreadInternal(EventUpdate, "PSPInputThread", 4096, NULL)) == NULL) { if ((thread = SDL_CreateThreadWithStackSize(EventUpdate, "PSPInputThread", 4096, NULL)) == NULL) {
return SDL_SetError("Can't create input thread"); return SDL_SetError("Can't create input thread");
} }
return 0; return 0;

View file

@ -105,7 +105,7 @@ void WINRT_CycleXAMLThread(void)
_mutex = SDL_CreateMutex(); _mutex = SDL_CreateMutex();
_threadState = ThreadState_Running; _threadState = ThreadState_Running;
_XAMLThread = SDL_CreateThreadInternal(WINRT_XAMLThreadMain, "SDL/XAML App Thread", 0, nullptr); _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr);
SDL_LockMutex(_mutex); SDL_LockMutex(_mutex);
while (_threadState != ThreadState_Yielding) { while (_threadState != ThreadState_Yielding) {