From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/thread/SDL_thread.c | 584 ------------------------------ 1 file changed, 584 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/thread/SDL_thread.c (limited to 'contrib/SDL-3.2.8/src/thread/SDL_thread.c') diff --git a/contrib/SDL-3.2.8/src/thread/SDL_thread.c b/contrib/SDL-3.2.8/src/thread/SDL_thread.c deleted file mode 100644 index 99cb9dd..0000000 --- a/contrib/SDL-3.2.8/src/thread/SDL_thread.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -// System independent thread management routines for SDL - -#include "SDL_thread_c.h" -#include "SDL_systhread.h" -#include "../SDL_error_c.h" - -// The storage is local to the thread, but the IDs are global for the process - -static SDL_AtomicInt SDL_tls_allocated; -static SDL_AtomicInt SDL_tls_id; - -void SDL_InitTLSData(void) -{ - SDL_SYS_InitTLSData(); -} - -void *SDL_GetTLS(SDL_TLSID *id) -{ - SDL_TLSData *storage; - int storage_index; - - if (id == NULL) { - SDL_InvalidParamError("id"); - return NULL; - } - - storage_index = SDL_GetAtomicInt(id) - 1; - storage = SDL_SYS_GetTLSData(); - if (!storage || storage_index < 0 || storage_index >= storage->limit) { - return NULL; - } - return storage->array[storage_index].data; -} - -bool SDL_SetTLS(SDL_TLSID *id, const void *value, SDL_TLSDestructorCallback destructor) -{ - SDL_TLSData *storage; - int storage_index; - - if (id == NULL) { - return SDL_InvalidParamError("id"); - } - - /* Make sure TLS is initialized. - * There's a race condition here if you are calling this from non-SDL threads - * and haven't called SDL_Init() on your main thread, but such is life. - */ - SDL_InitTLSData(); - - // Get the storage index associated with the ID in a thread-safe way - storage_index = SDL_GetAtomicInt(id) - 1; - if (storage_index < 0) { - int new_id = (SDL_AtomicIncRef(&SDL_tls_id) + 1); - - SDL_CompareAndSwapAtomicInt(id, 0, new_id); - - /* If there was a race condition we'll have wasted an ID, but every thread - * will have the same storage index for this id. - */ - storage_index = SDL_GetAtomicInt(id) - 1; - } - - // Get the storage for the current thread - storage = SDL_SYS_GetTLSData(); - if (!storage || storage_index >= storage->limit) { - unsigned int i, oldlimit, newlimit; - SDL_TLSData *new_storage; - - oldlimit = storage ? storage->limit : 0; - newlimit = (storage_index + TLS_ALLOC_CHUNKSIZE); - new_storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage) + (newlimit - 1) * sizeof(storage->array[0])); - if (!new_storage) { - return false; - } - storage = new_storage; - storage->limit = newlimit; - for (i = oldlimit; i < newlimit; ++i) { - storage->array[i].data = NULL; - storage->array[i].destructor = NULL; - } - if (!SDL_SYS_SetTLSData(storage)) { - SDL_free(storage); - return false; - } - SDL_AtomicIncRef(&SDL_tls_allocated); - } - - storage->array[storage_index].data = SDL_const_cast(void *, value); - storage->array[storage_index].destructor = destructor; - return true; -} - -void SDL_CleanupTLS(void) -{ - SDL_TLSData *storage; - - // Cleanup the storage for the current thread - storage = SDL_SYS_GetTLSData(); - if (storage) { - int i; - for (i = 0; i < storage->limit; ++i) { - if (storage->array[i].destructor) { - storage->array[i].destructor(storage->array[i].data); - } - } - SDL_SYS_SetTLSData(NULL); - SDL_free(storage); - (void)SDL_AtomicDecRef(&SDL_tls_allocated); - } -} - -void SDL_QuitTLSData(void) -{ - SDL_CleanupTLS(); - - if (SDL_GetAtomicInt(&SDL_tls_allocated) == 0) { - SDL_SYS_QuitTLSData(); - } else { - // Some thread hasn't called SDL_CleanupTLS() - } -} - -/* This is a generic implementation of thread-local storage which doesn't - require additional OS support. - - It is not especially efficient and doesn't clean up thread-local storage - as threads exit. If there is a real OS that doesn't support thread-local - storage this implementation should be improved to be production quality. -*/ - -typedef struct SDL_TLSEntry -{ - SDL_ThreadID thread; - SDL_TLSData *storage; - struct SDL_TLSEntry *next; -} SDL_TLSEntry; - -static SDL_Mutex *SDL_generic_TLS_mutex; -static SDL_TLSEntry *SDL_generic_TLS; - -void SDL_Generic_InitTLSData(void) -{ - if (!SDL_generic_TLS_mutex) { - SDL_generic_TLS_mutex = SDL_CreateMutex(); - } -} - -SDL_TLSData *SDL_Generic_GetTLSData(void) -{ - SDL_ThreadID thread = SDL_GetCurrentThreadID(); - SDL_TLSEntry *entry; - SDL_TLSData *storage = NULL; - - SDL_LockMutex(SDL_generic_TLS_mutex); - for (entry = SDL_generic_TLS; entry; entry = entry->next) { - if (entry->thread == thread) { - storage = entry->storage; - break; - } - } - SDL_UnlockMutex(SDL_generic_TLS_mutex); - - return storage; -} - -bool SDL_Generic_SetTLSData(SDL_TLSData *data) -{ - SDL_ThreadID thread = SDL_GetCurrentThreadID(); - SDL_TLSEntry *prev, *entry; - bool result = true; - - SDL_LockMutex(SDL_generic_TLS_mutex); - prev = NULL; - for (entry = SDL_generic_TLS; entry; entry = entry->next) { - if (entry->thread == thread) { - if (data) { - entry->storage = data; - } else { - if (prev) { - prev->next = entry->next; - } else { - SDL_generic_TLS = entry->next; - } - SDL_free(entry); - } - break; - } - prev = entry; - } - if (!entry && data) { - entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry)); - if (entry) { - entry->thread = thread; - entry->storage = data; - entry->next = SDL_generic_TLS; - SDL_generic_TLS = entry; - } else { - result = false; - } - } - SDL_UnlockMutex(SDL_generic_TLS_mutex); - - return result; -} - -void SDL_Generic_QuitTLSData(void) -{ - SDL_TLSEntry *entry; - - // This should have been cleaned up by the time we get here - SDL_assert(!SDL_generic_TLS); - if (SDL_generic_TLS) { - SDL_LockMutex(SDL_generic_TLS_mutex); - for (entry = SDL_generic_TLS; entry; ) { - SDL_TLSEntry *next = entry->next; - SDL_free(entry->storage); - SDL_free(entry); - entry = next; - } - SDL_generic_TLS = NULL; - SDL_UnlockMutex(SDL_generic_TLS_mutex); - } - - if (SDL_generic_TLS_mutex) { - SDL_DestroyMutex(SDL_generic_TLS_mutex); - SDL_generic_TLS_mutex = NULL; - } -} - -// Non-thread-safe global error variable -static SDL_error *SDL_GetStaticErrBuf(void) -{ - static SDL_error SDL_global_error; - static char SDL_global_error_str[128]; - SDL_global_error.str = SDL_global_error_str; - SDL_global_error.len = sizeof(SDL_global_error_str); - return &SDL_global_error; -} - -#ifndef SDL_THREADS_DISABLED -static void SDLCALL SDL_FreeErrBuf(void *data) -{ - SDL_error *errbuf = (SDL_error *)data; - - if (errbuf->str) { - errbuf->free_func(errbuf->str); - } - errbuf->free_func(errbuf); -} -#endif - -// Routine to get the thread-specific error variable -SDL_error *SDL_GetErrBuf(bool create) -{ -#ifdef SDL_THREADS_DISABLED - return SDL_GetStaticErrBuf(); -#else - static SDL_TLSID tls_errbuf; - SDL_error *errbuf; - - errbuf = (SDL_error *)SDL_GetTLS(&tls_errbuf); - if (!errbuf) { - if (!create) { - return NULL; - } - - /* Get the original memory functions for this allocation because the lifetime - * of the error buffer may span calls to SDL_SetMemoryFunctions() by the app - */ - SDL_realloc_func realloc_func; - SDL_free_func free_func; - SDL_GetOriginalMemoryFunctions(NULL, NULL, &realloc_func, &free_func); - - errbuf = (SDL_error *)realloc_func(NULL, sizeof(*errbuf)); - if (!errbuf) { - return SDL_GetStaticErrBuf(); - } - SDL_zerop(errbuf); - errbuf->realloc_func = realloc_func; - errbuf->free_func = free_func; - SDL_SetTLS(&tls_errbuf, errbuf, SDL_FreeErrBuf); - } - return errbuf; -#endif // SDL_THREADS_DISABLED -} - -static bool ThreadValid(SDL_Thread *thread) -{ - return SDL_ObjectValid(thread, SDL_OBJECT_TYPE_THREAD); -} - -void SDL_RunThread(SDL_Thread *thread) -{ - void *userdata = thread->userdata; - int(SDLCALL *userfunc)(void *) = thread->userfunc; - - int *statusloc = &thread->status; - - // Perform any system-dependent setup - this function may not fail - SDL_SYS_SetupThread(thread->name); - - // Get the thread id - thread->threadid = SDL_GetCurrentThreadID(); - - // Run the function - *statusloc = userfunc(userdata); - - // Clean up thread-local storage - SDL_CleanupTLS(); - - // Mark us as ready to be joined (or detached) - if (!SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_COMPLETE)) { - // Clean up if something already detached us. - if (SDL_GetThreadState(thread) == SDL_THREAD_DETACHED) { - SDL_free(thread->name); // Can't free later, we've already cleaned up TLS - SDL_free(thread); - } - } -} - -SDL_Thread *SDL_CreateThreadWithPropertiesRuntime(SDL_PropertiesID props, - SDL_FunctionPointer pfnBeginThread, - SDL_FunctionPointer pfnEndThread) -{ - // rather than check this in every backend, just make sure it's correct upfront. Only allow non-NULL if Windows, or Microsoft GDK. - #if !defined(SDL_PLATFORM_WINDOWS) - if (pfnBeginThread || pfnEndThread) { - SDL_SetError("_beginthreadex/_endthreadex not supported on this platform"); - return NULL; - } - #endif - - SDL_ThreadFunction fn = (SDL_ThreadFunction) SDL_GetPointerProperty(props, SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER, NULL); - const char *name = SDL_GetStringProperty(props, SDL_PROP_THREAD_CREATE_NAME_STRING, NULL); - const size_t stacksize = (size_t) SDL_GetNumberProperty(props, SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER, 0); - void *userdata = SDL_GetPointerProperty(props, SDL_PROP_THREAD_CREATE_USERDATA_POINTER, NULL); - - if (!fn) { - SDL_SetError("Thread entry function is NULL"); - return NULL; - } - - SDL_InitMainThread(); - - SDL_Thread *thread = (SDL_Thread *)SDL_calloc(1, sizeof(*thread)); - if (!thread) { - return NULL; - } - thread->status = -1; - SDL_SetAtomicInt(&thread->state, SDL_THREAD_ALIVE); - - // Set up the arguments for the thread - if (name) { - thread->name = SDL_strdup(name); - if (!thread->name) { - SDL_free(thread); - return NULL; - } - } - - thread->userfunc = fn; - thread->userdata = userdata; - thread->stacksize = stacksize; - - SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, true); - - // Create the thread and go! - if (!SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread)) { - // Oops, failed. Gotta free everything - SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false); - SDL_free(thread->name); - SDL_free(thread); - thread = NULL; - } - - // Everything is running now - return thread; -} - -SDL_Thread *SDL_CreateThreadRuntime(SDL_ThreadFunction fn, - const char *name, void *userdata, - SDL_FunctionPointer pfnBeginThread, - SDL_FunctionPointer pfnEndThread) -{ - const SDL_PropertiesID props = SDL_CreateProperties(); - SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER, (void *) fn); - SDL_SetStringProperty(props, SDL_PROP_THREAD_CREATE_NAME_STRING, name); - SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_USERDATA_POINTER, userdata); - SDL_Thread *thread = SDL_CreateThreadWithPropertiesRuntime(props, pfnBeginThread, pfnEndThread); - SDL_DestroyProperties(props); - return thread; -} - -// internal helper function, not in the public API. -SDL_Thread *SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn, const char *name, size_t stacksize, void *userdata) -{ - const SDL_PropertiesID props = SDL_CreateProperties(); - SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER, (void *) fn); - SDL_SetStringProperty(props, SDL_PROP_THREAD_CREATE_NAME_STRING, name); - SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_USERDATA_POINTER, userdata); - SDL_SetNumberProperty(props, SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER, (Sint64) stacksize); - SDL_Thread *thread = SDL_CreateThreadWithProperties(props); - SDL_DestroyProperties(props); - return thread; -} - -SDL_ThreadID SDL_GetThreadID(SDL_Thread *thread) -{ - SDL_ThreadID id = 0; - - if (thread) { - if (ThreadValid(thread)) { - id = thread->threadid; - } - } else { - id = SDL_GetCurrentThreadID(); - } - return id; -} - -const char *SDL_GetThreadName(SDL_Thread *thread) -{ - if (ThreadValid(thread)) { - return SDL_GetPersistentString(thread->name); - } else { - return NULL; - } -} - -bool SDL_SetCurrentThreadPriority(SDL_ThreadPriority priority) -{ - return SDL_SYS_SetThreadPriority(priority); -} - -void SDL_WaitThread(SDL_Thread *thread, int *status) -{ - if (!ThreadValid(thread)) { - if (status) { - *status = -1; - } - return; - } - - SDL_SYS_WaitThread(thread); - if (status) { - *status = thread->status; - } - SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false); - SDL_free(thread->name); - SDL_free(thread); -} - -SDL_ThreadState SDL_GetThreadState(SDL_Thread *thread) -{ - if (!ThreadValid(thread)) { - return SDL_THREAD_UNKNOWN; - } - - return (SDL_ThreadState)SDL_GetAtomicInt(&thread->state); -} - -void SDL_DetachThread(SDL_Thread *thread) -{ - if (!ThreadValid(thread)) { - return; - } - - // The thread may vanish at any time, it's no longer valid - SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false); - - // Grab dibs if the state is alive+joinable. - if (SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_DETACHED)) { - SDL_SYS_DetachThread(thread); - } else { - // all other states are pretty final, see where we landed. - SDL_ThreadState thread_state = SDL_GetThreadState(thread); - if (thread_state == SDL_THREAD_DETACHED) { - return; // already detached (you shouldn't call this twice!) - } else if (thread_state == SDL_THREAD_COMPLETE) { - SDL_WaitThread(thread, NULL); // already done, clean it up. - } - } -} - -void SDL_WaitSemaphore(SDL_Semaphore *sem) -{ - SDL_WaitSemaphoreTimeoutNS(sem, -1); -} - -bool SDL_TryWaitSemaphore(SDL_Semaphore *sem) -{ - return SDL_WaitSemaphoreTimeoutNS(sem, 0); -} - -bool SDL_WaitSemaphoreTimeout(SDL_Semaphore *sem, Sint32 timeoutMS) -{ - Sint64 timeoutNS; - - if (timeoutMS >= 0) { - timeoutNS = SDL_MS_TO_NS(timeoutMS); - } else { - timeoutNS = -1; - } - return SDL_WaitSemaphoreTimeoutNS(sem, timeoutNS); -} - -void SDL_WaitCondition(SDL_Condition *cond, SDL_Mutex *mutex) -{ - SDL_WaitConditionTimeoutNS(cond, mutex, -1); -} - -bool SDL_WaitConditionTimeout(SDL_Condition *cond, SDL_Mutex *mutex, Sint32 timeoutMS) -{ - Sint64 timeoutNS; - - if (timeoutMS >= 0) { - timeoutNS = SDL_MS_TO_NS(timeoutMS); - } else { - timeoutNS = -1; - } - return SDL_WaitConditionTimeoutNS(cond, mutex, timeoutNS); -} - -bool SDL_ShouldInit(SDL_InitState *state) -{ - while (SDL_GetAtomicInt(&state->status) != SDL_INIT_STATUS_INITIALIZED) { - if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED, SDL_INIT_STATUS_INITIALIZING)) { - state->thread = SDL_GetCurrentThreadID(); - return true; - } - - // Wait for the other thread to complete transition - SDL_Delay(1); - } - return false; -} - -bool SDL_ShouldQuit(SDL_InitState *state) -{ - while (SDL_GetAtomicInt(&state->status) != SDL_INIT_STATUS_UNINITIALIZED) { - if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED, SDL_INIT_STATUS_UNINITIALIZING)) { - state->thread = SDL_GetCurrentThreadID(); - return true; - } - - // Wait for the other thread to complete transition - SDL_Delay(1); - } - return false; -} - -void SDL_SetInitialized(SDL_InitState *state, bool initialized) -{ - SDL_assert(state->thread == SDL_GetCurrentThreadID()); - - if (initialized) { - SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED); - } else { - SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED); - } -} - -- cgit v1.2.3