diff --git a/docs/README-migration.md b/docs/README-migration.md index c0794c98d0..f8d33a0d23 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -1630,6 +1630,8 @@ becomes: ## 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: * SDL_TLSCleanup() => SDL_CleanupTLS() * SDL_TLSCreate() => SDL_CreateTLS() diff --git a/include/SDL3/SDL_thread.h b/include/SDL3/SDL_thread.h index 2f23115759..e830470569 100644 --- a/include/SDL3/SDL_thread.h +++ b/include/SDL3/SDL_thread.h @@ -45,14 +45,44 @@ extern "C" { #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; -/* 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; -/* 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; /** @@ -74,7 +104,7 @@ typedef enum 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() * \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); -/* - * 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) -#define SDL_PASSED_BEGINTHREAD_ENDTHREAD -typedef uintptr_t (__cdecl * pfnSDL_CurrentBeginThread) - (void *, unsigned, unsigned (__stdcall *func)(void *), - void * /*arg*/, unsigned, unsigned * /* threadID */); -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 +#ifndef SDL_BeginThreadFunction +/** + * Macro that manages the compiler's `_beginthreadex` implementation. * - * \param fn Thread function - * \param name name - * \param data some data - * \param pfnBeginThread begin function - * \param pfnEndThread end function + * On Windows (and maybe other platforms), a program might use a different + * C runtime than its libraries. Or, in SDL's case, it might use a C runtime + * while SDL uses none at all. * - * \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 -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) +#define SDL_BeginThreadFunction _beginthreadex #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. @@ -178,6 +203,16 @@ SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, * 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 name the name of the thread * \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 * 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 name the name of the thread * \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 */ 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 /** diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index d86cf133b5..c6645943ef 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1633,10 +1633,9 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec // Start the audio thread if necessary if (!current_audio.impl.ProvidesOwnCallbackThread) { - const size_t stacksize = 0; // just take the system default, since audio streams might have callbacks. char threadname[64]; 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) { ClosePhysicalAudioDevice(device); diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m index 8de8d96c05..44cd6d9ca0 100644 --- a/src/audio/coreaudio/SDL_coreaudio.m +++ b/src/audio/coreaudio/SDL_coreaudio.m @@ -952,7 +952,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device) char threadname[64]; 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) { return -1; } diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 1898a19e26..e36e368388 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -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... 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_DestroySemaphore(ready_sem); } diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index c7d0fb3282..54322742d3 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -210,7 +210,7 @@ static int InitManagementThread(void) SDL_AtomicSetPtr((void **) &ManagementThreadPendingTasks, NULL); 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) { return -1; } diff --git a/src/camera/SDL_camera.c b/src/camera/SDL_camera.c index 081b3df408..3b337fb896 100644 --- a/src/camera/SDL_camera.c +++ b/src/camera/SDL_camera.c @@ -1150,7 +1150,7 @@ SDL_Camera *SDL_OpenCameraDevice(SDL_CameraDeviceID instance_id, const SDL_Camer if (!camera_driver.impl.ProvidesOwnCallbackThread) { char threadname[64]; SDL_GetCameraThreadName(device, threadname, sizeof (threadname)); - device->thread = SDL_CreateThreadInternal(CameraThread, threadname, 0, device); + device->thread = SDL_CreateThread(CameraThread, threadname, device); if (!device->thread) { ClosePhysicalCameraDevice(device); ReleaseCameraDevice(device); diff --git a/src/core/haiku/SDL_BeApp.cc b/src/core/haiku/SDL_BeApp.cc index 68a79f4e30..ba0f256e3c 100644 --- a/src/core/haiku/SDL_BeApp.cc +++ b/src/core/haiku/SDL_BeApp.cc @@ -107,7 +107,7 @@ static int StartBeApp(void *unused) static int StartBeLooper() { if (!be_app) { - SDL_AppThread = SDL_CreateThreadInternal(StartBeApp, "SDLApplication", 0, NULL); + SDL_AppThread = SDL_CreateThread(StartBeApp, "SDLApplication", NULL); if (!SDL_AppThread) { return SDL_SetError("Couldn't create BApplication thread"); } diff --git a/src/dialog/windows/SDL_windowsdialog.c b/src/dialog/windows/SDL_windowsdialog.c index f02792e763..d749c711bf 100644 --- a/src/dialog/windows/SDL_windowsdialog.c +++ b/src/dialog/windows/SDL_windowsdialog.c @@ -459,7 +459,7 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL args->callback = callback; 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) { callback(userdata, NULL, -1); @@ -495,7 +495,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL args->callback = callback; 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) { callback(userdata, NULL, -1); @@ -528,7 +528,7 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S args->default_folder = default_location; 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) { callback(userdata, NULL, -1); diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index bca7ca5405..82c6165c31 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -84,8 +84,8 @@ SDL3_0.0.0 { SDL_CreateTexture; SDL_CreateTextureFromSurface; SDL_CreateTextureWithProperties; - SDL_CreateThread; - SDL_CreateThreadWithStackSize; + SDL_CreateThreadRuntime; + SDL_CreateThreadWithStackSizeRuntime; SDL_CreateWindow; SDL_CreateWindowAndRenderer; SDL_CreateWindowWithProperties; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index ae7e584dbe..45b44358de 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -109,8 +109,8 @@ #define SDL_CreateTexture SDL_CreateTexture_REAL #define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL #define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL -#define SDL_CreateThread SDL_CreateThread_REAL -#define SDL_CreateThreadWithStackSize SDL_CreateThreadWithStackSize_REAL +#define SDL_CreateThreadRuntime SDL_CreateThreadRuntime_REAL +#define SDL_CreateThreadWithStackSizeRuntime SDL_CreateThreadWithStackSizeRuntime_REAL #define SDL_CreateWindow SDL_CreateWindow_REAL #define SDL_CreateWindowAndRenderer SDL_CreateWindowAndRenderer_REAL #define SDL_CreateWindowWithProperties SDL_CreateWindowWithProperties_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index a9cd547fb7..67a2121633 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -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) #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 */ 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) @@ -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_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_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(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) diff --git a/src/hidapi/libusb/hidapi_thread_sdl.h b/src/hidapi/libusb/hidapi_thread_sdl.h index 78b7e09eb5..fc27721c7e 100644 --- a/src/hidapi/libusb/hidapi_thread_sdl.h +++ b/src/hidapi/libusb/hidapi_thread_sdl.h @@ -179,7 +179,7 @@ static void hidapi_thread_create(hidapi_thread_state *state, void *(*func)(void* */ param->func = func; 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) diff --git a/src/joystick/hidapi/SDL_hidapi_rumble.c b/src/joystick/hidapi/SDL_hidapi_rumble.c index 8dd7316c1e..a639823637 100644 --- a/src/joystick/hidapi/SDL_hidapi_rumble.c +++ b/src/joystick/hidapi/SDL_hidapi_rumble.c @@ -156,7 +156,7 @@ static int SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx) } 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) { SDL_HIDAPI_StopRumbleThread(ctx); return -1; diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index 6bd204ae42..e5dcdbf657 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -286,7 +286,7 @@ static int SDL_StartJoystickThread(void) } 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) { return -1; } diff --git a/src/sensor/android/SDL_androidsensor.c b/src/sensor/android/SDL_androidsensor.c index 5b58671475..b832974e9a 100644 --- a/src/sensor/android/SDL_androidsensor.c +++ b/src/sensor/android/SDL_androidsensor.c @@ -120,7 +120,7 @@ static int SDL_ANDROID_StartSensorThread(SDL_AndroidSensorThreadContext *ctx) } 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) { SDL_ANDROID_StopSensorThread(ctx); return -1; diff --git a/src/thread/SDL_systhread.h b/src/thread/SDL_systhread.h index 70df324c68..c3370221dd 100644 --- a/src/thread/SDL_systhread.h +++ b/src/thread/SDL_systhread.h @@ -36,13 +36,9 @@ extern "C" { saves a system-dependent thread id in thread->id, and returns 0 on success. */ -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD extern int SDL_SYS_CreateThread(SDL_Thread *thread, - pfnSDL_CurrentBeginThread pfnBeginThread, - pfnSDL_CurrentEndThread pfnEndThread); -#else -extern int SDL_SYS_CreateThread(SDL_Thread *thread); -#endif + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread); /* This function does any necessary setup in the child thread */ 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 */ 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++ */ #ifdef __cplusplus } diff --git a/src/thread/SDL_thread.c b/src/thread/SDL_thread.c index 1a1348e349..31340253eb 100644 --- a/src/thread/SDL_thread.c +++ b/src/thread/SDL_thread.c @@ -307,28 +307,22 @@ void SDL_RunThread(SDL_Thread *thread) } } -#ifdef SDL_CreateThread -#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 *), +SDL_Thread *SDL_CreateThreadWithStackSizeRuntime(SDL_ThreadFunction fn, const char *name, const size_t stacksize, void *data, - pfnSDL_CurrentBeginThread pfnBeginThread, - pfnSDL_CurrentEndThread pfnEndThread) -#else -SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *), - const char *name, const size_t stacksize, void *data) -#endif + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { SDL_Thread *thread; 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 */ thread = (SDL_Thread *)SDL_calloc(1, sizeof(*thread)); if (!thread) { @@ -351,11 +345,7 @@ SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *), thread->stacksize = stacksize; /* Create the thread and go! */ -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD ret = SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread); -#else - ret = SDL_SYS_CreateThread(thread); -#endif if (ret < 0) { /* Oops, failed. Gotta free everything */ SDL_free(thread->name); @@ -367,31 +357,12 @@ SDL_Thread *SDL_CreateThreadWithStackSize(int(SDLCALL *fn)(void *), return thread; } -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD -SDL_Thread *SDLCALL SDL_CreateThread(int(SDLCALL *fn)(void *), +SDL_Thread *SDL_CreateThreadRuntime(SDL_ThreadFunction fn, const char *name, void *data, - pfnSDL_CurrentBeginThread pfnBeginThread, - pfnSDL_CurrentEndThread pfnEndThread) -#else -SDL_Thread *SDLCALL SDL_CreateThread(int(SDLCALL *fn)(void *), - const char *name, void *data) -#endif + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD - 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 + return SDL_CreateThreadWithStackSizeRuntime(fn, name, 0, data, pfnBeginThread, pfnEndThread); } SDL_ThreadID SDL_GetThreadID(SDL_Thread *thread) diff --git a/src/thread/generic/SDL_systhread.c b/src/thread/generic/SDL_systhread.c index 5a2a3a71b0..d622732648 100644 --- a/src/thread/generic/SDL_systhread.c +++ b/src/thread/generic/SDL_systhread.c @@ -24,13 +24,9 @@ #include "../SDL_systhread.h" -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD int SDL_SYS_CreateThread(SDL_Thread *thread, - pfnSDL_CurrentBeginThread pfnBeginThread, - pfnSDL_CurrentEndThread pfnEndThread) -#else -int SDL_SYS_CreateThread(SDL_Thread *thread) -#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { return SDL_SetError("Threads are not supported on this platform"); } diff --git a/src/thread/n3ds/SDL_systhread.c b/src/thread/n3ds/SDL_systhread.c index 5a279e0eaa..68d8546cf2 100644 --- a/src/thread/n3ds/SDL_systhread.c +++ b/src/thread/n3ds/SDL_systhread.c @@ -42,11 +42,10 @@ static void ThreadEntry(void *arg) 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; int cpu = -1; diff --git a/src/thread/ngage/SDL_systhread.cpp b/src/thread/ngage/SDL_systhread.cpp index ded1ce35ad..de51dff9bb 100644 --- a/src/thread/ngage/SDL_systhread.cpp +++ b/src/thread/ngage/SDL_systhread.cpp @@ -57,7 +57,9 @@ int CreateUnique(TInt (*aFunc)(const TDesC &aName, TAny *, TAny *), TAny *aPtr1, return status; } -int SDL_SYS_CreateThread(SDL_Thread *thread) +int SDL_SYS_CreateThread(SDL_Thread *thread, + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { RThread rthread; diff --git a/src/thread/ps2/SDL_systhread.c b/src/thread/ps2/SDL_systhread.c index 2c3a57e521..c52ecbdbdf 100644 --- a/src/thread/ps2/SDL_systhread.c +++ b/src/thread/ps2/SDL_systhread.c @@ -54,7 +54,9 @@ static int childThread(void *arg) 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_t eethread; diff --git a/src/thread/psp/SDL_systhread.c b/src/thread/psp/SDL_systhread.c index 558a3282dd..df60cc16a3 100644 --- a/src/thread/psp/SDL_systhread.c +++ b/src/thread/psp/SDL_systhread.c @@ -38,7 +38,9 @@ static int ThreadEntry(SceSize args, void *argp) return 0; } -int SDL_SYS_CreateThread(SDL_Thread *thread) +int SDL_SYS_CreateThread(SDL_Thread *thread, + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { SceKernelThreadInfo status; int priority = 32; diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index 1d0fe77e42..3f9aa4d05f 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -77,7 +77,9 @@ static int (*ppthread_setname_np)(const char *) = NULL; static SDL_bool checked_setname = SDL_FALSE; static int (*ppthread_setname_np)(pthread_t, const char *) = NULL; #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; diff --git a/src/thread/stdcpp/SDL_systhread.cpp b/src/thread/stdcpp/SDL_systhread.cpp index c3ef90a34d..06bc933ed9 100644 --- a/src/thread/stdcpp/SDL_systhread.cpp +++ b/src/thread/stdcpp/SDL_systhread.cpp @@ -41,7 +41,9 @@ static void RunThread(void *args) } extern "C" int -SDL_SYS_CreateThread(SDL_Thread *thread) +SDL_SYS_CreateThread(SDL_Thread *thread, + SDL_FunctionPointer pfnBeginThread, + SDL_FunctionPointer pfnEndThread) { try { // !!! FIXME: no way to set a thread stack size here. diff --git a/src/thread/vita/SDL_systhread.c b/src/thread/vita/SDL_systhread.c index 545083fe04..9230641d27 100644 --- a/src/thread/vita/SDL_systhread.c +++ b/src/thread/vita/SDL_systhread.c @@ -48,7 +48,10 @@ static int ThreadEntry(SceSize args, void *argp) 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]; size_t stack_size = VITA_THREAD_STACK_SIZE_DEFAULT; diff --git a/src/thread/windows/SDL_systhread.c b/src/thread/windows/SDL_systhread.c index b3ae5adc06..8653fe1180 100644 --- a/src/thread/windows/SDL_systhread.c +++ b/src/thread/windows/SDL_systhread.c @@ -32,20 +32,15 @@ #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 #endif -#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD -/* We'll use the C library from this DLL */ -#include -typedef uintptr_t(__cdecl *pfnSDL_CurrentBeginThread)(void *, unsigned, - unsigned(__stdcall *func)(void*), - void *arg, unsigned, - unsigned *threadID); -typedef void(__cdecl *pfnSDL_CurrentEndThread)(unsigned code); -#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */ +typedef void (__cdecl * SDL_EndThreadExCallback) (unsigned retval); +typedef uintptr_t (__cdecl * SDL_BeginThreadExCallback) + (void *security, unsigned stacksize, unsigned (__stdcall *startaddr)(void *), + void * arglist, unsigned initflag, unsigned *threadaddr); static DWORD RunThread(void *data) { SDL_Thread *thread = (SDL_Thread *)data; - pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)thread->endfunc; + SDL_EndThreadExCallback pfnEndThread = (SDL_EndThreadExCallback)thread->endfunc; SDL_RunThread(thread); if (pfnEndThread) { pfnEndThread(0); @@ -63,26 +58,16 @@ static unsigned __stdcall MINGW32_FORCEALIGN RunThreadViaBeginThreadEx(void *dat return (unsigned)RunThread(data); } -#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD int SDL_SYS_CreateThread(SDL_Thread *thread, - pfnSDL_CurrentBeginThread pfnBeginThread, - pfnSDL_CurrentEndThread pfnEndThread) + SDL_FunctionPointer vpfnBeginThread, + SDL_FunctionPointer vpfnEndThread) { -#elif defined(SDL_PLATFORM_CYGWIN) || defined(SDL_PLATFORM_WINRT) -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 */ + SDL_BeginThreadExCallback pfnBeginThread = (SDL_BeginThreadExCallback) vpfnBeginThread; + 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! */ - thread->endfunc = (SDL_FunctionPointer)pfnEndThread; + thread->endfunc = vpfnEndThread; /* thread->stacksize == 0 means "system default", same as win32 expects */ if (pfnBeginThread) { diff --git a/src/timer/SDL_timer.c b/src/timer/SDL_timer.c index f7ffe6ba33..b779c7c3f3 100644 --- a/src/timer/SDL_timer.c +++ b/src/timer/SDL_timer.c @@ -221,7 +221,7 @@ int SDL_InitTimers(void) SDL_AtomicSet(&data->active, 1); /* 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) { SDL_QuitTimers(); return -1; diff --git a/src/video/psp/SDL_pspevents.c b/src/video/psp/SDL_pspevents.c index 0e1fd9dc10..80ec27b017 100644 --- a/src/video/psp/SDL_pspevents.c +++ b/src/video/psp/SDL_pspevents.c @@ -252,7 +252,7 @@ int PSP_EventInit(SDL_VideoDevice *_this) return SDL_SetError("Can't create input semaphore"); } 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 0; diff --git a/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp index 0a4cdaaba4..f5be65f88d 100644 --- a/src/video/winrt/SDL_winrtevents.cpp +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -105,7 +105,7 @@ void WINRT_CycleXAMLThread(void) _mutex = SDL_CreateMutex(); _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); while (_threadState != ThreadState_Yielding) {