diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/thread')
33 files changed, 4250 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/thread/SDL_systhread.h b/source/3rd-party/SDL2/src/thread/SDL_systhread.h new file mode 100644 index 0000000..1862b23 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/SDL_systhread.h @@ -0,0 +1,70 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* These are functions that need to be implemented by a port of SDL */ + +#ifndef SDL_systhread_h_ +#define SDL_systhread_h_ + +#include "SDL_thread.h" +#include "SDL_thread_c.h" + +/* This function creates a thread, passing args to SDL_RunThread(), + 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, void *args, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread); +#else +extern int SDL_SYS_CreateThread(SDL_Thread * thread, void *args); +#endif + +/* This function does any necessary setup in the child thread */ +extern void SDL_SYS_SetupThread(const char *name); + +/* This function sets the current thread priority */ +extern int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority); + +/* This function waits for the thread to finish and frees any data + allocated by SDL_SYS_CreateThread() + */ +extern void SDL_SYS_WaitThread(SDL_Thread * thread); + +/* Mark thread as cleaned up as soon as it exits, without joining. */ +extern void SDL_SYS_DetachThread(SDL_Thread * thread); + +/* Get the thread local storage for this thread */ +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); + +#endif /* SDL_systhread_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/SDL_thread.c b/source/3rd-party/SDL2/src/thread/SDL_thread.c new file mode 100644 index 0000000..5570adb --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/SDL_thread.c @@ -0,0 +1,505 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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_assert.h" +#include "SDL_thread.h" +#include "SDL_thread_c.h" +#include "SDL_systhread.h" +#include "SDL_hints.h" +#include "../SDL_error_c.h" + + +SDL_TLSID +SDL_TLSCreate() +{ + static SDL_atomic_t SDL_tls_id; + return SDL_AtomicIncRef(&SDL_tls_id)+1; +} + +void * +SDL_TLSGet(SDL_TLSID id) +{ + SDL_TLSData *storage; + + storage = SDL_SYS_GetTLSData(); + if (!storage || id == 0 || id > storage->limit) { + return NULL; + } + return storage->array[id-1].data; +} + +int +SDL_TLSSet(SDL_TLSID id, const void *value, void (SDLCALL *destructor)(void *)) +{ + SDL_TLSData *storage; + + if (id == 0) { + return SDL_InvalidParamError("id"); + } + + storage = SDL_SYS_GetTLSData(); + if (!storage || (id > storage->limit)) { + unsigned int i, oldlimit, newlimit; + + oldlimit = storage ? storage->limit : 0; + newlimit = (id + TLS_ALLOC_CHUNKSIZE); + storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage)+(newlimit-1)*sizeof(storage->array[0])); + if (!storage) { + return SDL_OutOfMemory(); + } + storage->limit = newlimit; + for (i = oldlimit; i < newlimit; ++i) { + storage->array[i].data = NULL; + storage->array[i].destructor = NULL; + } + if (SDL_SYS_SetTLSData(storage) != 0) { + return -1; + } + } + + storage->array[id-1].data = SDL_const_cast(void*, value); + storage->array[id-1].destructor = destructor; + return 0; +} + +static void +SDL_TLSCleanup() +{ + SDL_TLSData *storage; + + storage = SDL_SYS_GetTLSData(); + if (storage) { + unsigned 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); + } +} + + +/* 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; + + +SDL_TLSData * +SDL_Generic_GetTLSData(void) +{ + SDL_threadID thread = SDL_ThreadID(); + SDL_TLSEntry *entry; + SDL_TLSData *storage = NULL; + +#if !SDL_THREADS_DISABLED + if (!SDL_generic_TLS_mutex) { + static SDL_SpinLock tls_lock; + SDL_AtomicLock(&tls_lock); + if (!SDL_generic_TLS_mutex) { + SDL_mutex *mutex = SDL_CreateMutex(); + SDL_MemoryBarrierRelease(); + SDL_generic_TLS_mutex = mutex; + if (!SDL_generic_TLS_mutex) { + SDL_AtomicUnlock(&tls_lock); + return NULL; + } + } + SDL_AtomicUnlock(&tls_lock); + } +#endif /* SDL_THREADS_DISABLED */ + + SDL_MemoryBarrierAcquire(); + SDL_LockMutex(SDL_generic_TLS_mutex); + for (entry = SDL_generic_TLS; entry; entry = entry->next) { + if (entry->thread == thread) { + storage = entry->storage; + break; + } + } +#if !SDL_THREADS_DISABLED + SDL_UnlockMutex(SDL_generic_TLS_mutex); +#endif + + return storage; +} + +int +SDL_Generic_SetTLSData(SDL_TLSData *storage) +{ + SDL_threadID thread = SDL_ThreadID(); + SDL_TLSEntry *prev, *entry; + + /* SDL_Generic_GetTLSData() is always called first, so we can assume SDL_generic_TLS_mutex */ + SDL_LockMutex(SDL_generic_TLS_mutex); + prev = NULL; + for (entry = SDL_generic_TLS; entry; entry = entry->next) { + if (entry->thread == thread) { + if (storage) { + entry->storage = storage; + } else { + if (prev) { + prev->next = entry->next; + } else { + SDL_generic_TLS = entry->next; + } + SDL_free(entry); + } + break; + } + prev = entry; + } + if (!entry) { + entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry)); + if (entry) { + entry->thread = thread; + entry->storage = storage; + entry->next = SDL_generic_TLS; + SDL_generic_TLS = entry; + } + } + SDL_UnlockMutex(SDL_generic_TLS_mutex); + + if (!entry) { + return SDL_OutOfMemory(); + } + return 0; +} + +/* Routine to get the thread-specific error variable */ +SDL_error * +SDL_GetErrBuf(void) +{ + static SDL_SpinLock tls_lock; + static SDL_bool tls_being_created; + static SDL_TLSID tls_errbuf; + static SDL_error SDL_global_errbuf; + const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1; + SDL_error *errbuf; + + /* tls_being_created is there simply to prevent recursion if SDL_TLSCreate() fails. + It also means it's possible for another thread to also use SDL_global_errbuf, + but that's very unlikely and hopefully won't cause issues. + */ + if (!tls_errbuf && !tls_being_created) { + SDL_AtomicLock(&tls_lock); + if (!tls_errbuf) { + SDL_TLSID slot; + tls_being_created = SDL_TRUE; + slot = SDL_TLSCreate(); + tls_being_created = SDL_FALSE; + SDL_MemoryBarrierRelease(); + tls_errbuf = slot; + } + SDL_AtomicUnlock(&tls_lock); + } + if (!tls_errbuf) { + return &SDL_global_errbuf; + } + + SDL_MemoryBarrierAcquire(); + errbuf = (SDL_error *)SDL_TLSGet(tls_errbuf); + if (errbuf == ALLOCATION_IN_PROGRESS) { + return &SDL_global_errbuf; + } + if (!errbuf) { + /* Mark that we're in the middle of allocating our buffer */ + SDL_TLSSet(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL); + errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf)); + if (!errbuf) { + SDL_TLSSet(tls_errbuf, NULL, NULL); + return &SDL_global_errbuf; + } + SDL_zerop(errbuf); + SDL_TLSSet(tls_errbuf, errbuf, SDL_free); + } + return errbuf; +} + + +/* Arguments and callback to setup and run the user thread function */ +typedef struct +{ + int (SDLCALL * func) (void *); + void *data; + SDL_Thread *info; + SDL_sem *wait; +} thread_args; + +void +SDL_RunThread(void *data) +{ + thread_args *args = (thread_args *) data; + int (SDLCALL * userfunc) (void *) = args->func; + void *userdata = args->data; + SDL_Thread *thread = args->info; + 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_ThreadID(); + + /* Wake up the parent thread */ + SDL_SemPost(args->wait); + + /* Run the function */ + *statusloc = userfunc(userdata); + + /* Clean up thread-local storage */ + SDL_TLSCleanup(); + + /* Mark us as ready to be joined (or detached) */ + if (!SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_ZOMBIE)) { + /* Clean up if something already detached us. */ + if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_DETACHED, SDL_THREAD_STATE_CLEANED)) { + if (thread->name) { + SDL_free(thread->name); + } + SDL_free(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 *), + 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_Thread *thread; + thread_args *args; + int ret; + + /* Allocate memory for the thread info structure */ + thread = (SDL_Thread *) SDL_malloc(sizeof(*thread)); + if (thread == NULL) { + SDL_OutOfMemory(); + return (NULL); + } + SDL_zerop(thread); + thread->status = -1; + SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE); + + /* Set up the arguments for the thread */ + if (name != NULL) { + thread->name = SDL_strdup(name); + if (thread->name == NULL) { + SDL_OutOfMemory(); + SDL_free(thread); + return (NULL); + } + } + + /* Set up the arguments for the thread */ + args = (thread_args *) SDL_malloc(sizeof(*args)); + if (args == NULL) { + SDL_OutOfMemory(); + if (thread->name) { + SDL_free(thread->name); + } + SDL_free(thread); + return (NULL); + } + args->func = fn; + args->data = data; + args->info = thread; + args->wait = SDL_CreateSemaphore(0); + if (args->wait == NULL) { + if (thread->name) { + SDL_free(thread->name); + } + SDL_free(thread); + SDL_free(args); + return (NULL); + } + + thread->stacksize = stacksize; + + /* Create the thread and go! */ +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread); +#else + ret = SDL_SYS_CreateThread(thread, args); +#endif + if (ret >= 0) { + /* Wait for the thread function to use arguments */ + SDL_SemWait(args->wait); + } else { + /* Oops, failed. Gotta free everything */ + if (thread->name) { + SDL_free(thread->name); + } + SDL_free(thread); + thread = NULL; + } + SDL_DestroySemaphore(args->wait); + SDL_free(args); + + /* Everything is running now */ + return (thread); +} + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +DECLSPEC SDL_Thread *SDLCALL +SDL_CreateThread(int (SDLCALL * fn) (void *), + const char *name, void *data, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread) +#else +DECLSPEC SDL_Thread *SDLCALL +SDL_CreateThread(int (SDLCALL * fn) (void *), + const char *name, void *data) +#endif +{ + /* !!! FIXME: in 2.1, just make stackhint part of the usual API. */ + const char *stackhint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE); + size_t stacksize = 0; + + /* If the SDL_HINT_THREAD_STACK_SIZE exists, use it */ + if (stackhint != NULL) { + char *endp = NULL; + const Sint64 hintval = SDL_strtoll(stackhint, &endp, 10); + if ((*stackhint != '\0') && (*endp == '\0')) { /* a valid number? */ + if (hintval > 0) { /* reject bogus values. */ + stacksize = (size_t) hintval; + } + } + } + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, pfnBeginThread, pfnEndThread); +#else + return SDL_CreateThreadWithStackSize(fn, name, stacksize, 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 id; + + if (thread) { + id = thread->threadid; + } else { + id = SDL_ThreadID(); + } + return id; +} + +const char * +SDL_GetThreadName(SDL_Thread * thread) +{ + if (thread) { + return thread->name; + } else { + return NULL; + } +} + +int +SDL_SetThreadPriority(SDL_ThreadPriority priority) +{ + return SDL_SYS_SetThreadPriority(priority); +} + +void +SDL_WaitThread(SDL_Thread * thread, int *status) +{ + if (thread) { + SDL_SYS_WaitThread(thread); + if (status) { + *status = thread->status; + } + if (thread->name) { + SDL_free(thread->name); + } + SDL_free(thread); + } +} + +void +SDL_DetachThread(SDL_Thread * thread) +{ + if (!thread) { + return; + } + + /* Grab dibs if the state is alive+joinable. */ + if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_DETACHED)) { + SDL_SYS_DetachThread(thread); + } else { + /* all other states are pretty final, see where we landed. */ + const int thread_state = SDL_AtomicGet(&thread->state); + if ((thread_state == SDL_THREAD_STATE_DETACHED) || (thread_state == SDL_THREAD_STATE_CLEANED)) { + return; /* already detached (you shouldn't call this twice!) */ + } else if (thread_state == SDL_THREAD_STATE_ZOMBIE) { + SDL_WaitThread(thread, NULL); /* already done, clean it up. */ + } else { + SDL_assert(0 && "Unexpected thread state"); + } + } +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/SDL_thread_c.h b/source/3rd-party/SDL2/src/thread/SDL_thread_c.h new file mode 100644 index 0000000..b68f90e --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/SDL_thread_c.h @@ -0,0 +1,95 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#ifndef SDL_thread_c_h_ +#define SDL_thread_c_h_ + +#include "SDL_thread.h" + +/* Need the definitions of SYS_ThreadHandle */ +#if SDL_THREADS_DISABLED +#include "generic/SDL_systhread_c.h" +#elif SDL_THREAD_PTHREAD +#include "pthread/SDL_systhread_c.h" +#elif SDL_THREAD_WINDOWS +#include "windows/SDL_systhread_c.h" +#elif SDL_THREAD_PSP +#include "psp/SDL_systhread_c.h" +#elif SDL_THREAD_STDCPP +#include "stdcpp/SDL_systhread_c.h" +#else +#error Need thread implementation for this platform +#include "generic/SDL_systhread_c.h" +#endif +#include "../SDL_error_c.h" + +typedef enum SDL_ThreadState +{ + SDL_THREAD_STATE_ALIVE, + SDL_THREAD_STATE_DETACHED, + SDL_THREAD_STATE_ZOMBIE, + SDL_THREAD_STATE_CLEANED, +} SDL_ThreadState; + +/* This is the system-independent thread info structure */ +struct SDL_Thread +{ + SDL_threadID threadid; + SYS_ThreadHandle handle; + int status; + SDL_atomic_t state; /* SDL_THREAD_STATE_* */ + SDL_error errbuf; + char *name; + size_t stacksize; /* 0 for default, >0 for user-specified stack size. */ + void *data; +}; + +/* This is the function called to run a thread */ +extern void SDL_RunThread(void *data); + +/* This is the system-independent thread local storage structure */ +typedef struct { + unsigned int limit; + struct { + void *data; + void (SDLCALL *destructor)(void*); + } array[1]; +} SDL_TLSData; + +/* This is how many TLS entries we allocate at once */ +#define TLS_ALLOC_CHUNKSIZE 4 + +/* Get cross-platform, slow, thread local storage for this thread. + This is only intended as a fallback if getting real thread-local + storage fails or isn't supported on this platform. + */ +extern SDL_TLSData *SDL_Generic_GetTLSData(void); + +/* Set cross-platform, slow, thread local storage for this thread. + This is only intended as a fallback if getting real thread-local + storage fails or isn't supported on this platform. + */ +extern int SDL_Generic_SetTLSData(SDL_TLSData *data); + +#endif /* SDL_thread_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_syscond.c b/source/3rd-party/SDL2/src/thread/generic/SDL_syscond.c new file mode 100644 index 0000000..34b9893 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_syscond.c @@ -0,0 +1,220 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* An implementation of condition variables using semaphores and mutexes */ +/* + This implementation borrows heavily from the BeOS condition variable + implementation, written by Christopher Tate and Owen Smith. Thanks! + */ + +#include "SDL_thread.h" + +struct SDL_cond +{ + SDL_mutex *lock; + int waiting; + int signals; + SDL_sem *wait_sem; + SDL_sem *wait_done; +}; + +/* Create a condition variable */ +SDL_cond * +SDL_CreateCond(void) +{ + SDL_cond *cond; + + cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); + if (cond) { + cond->lock = SDL_CreateMutex(); + cond->wait_sem = SDL_CreateSemaphore(0); + cond->wait_done = SDL_CreateSemaphore(0); + cond->waiting = cond->signals = 0; + if (!cond->lock || !cond->wait_sem || !cond->wait_done) { + SDL_DestroyCond(cond); + cond = NULL; + } + } else { + SDL_OutOfMemory(); + } + return (cond); +} + +/* Destroy a condition variable */ +void +SDL_DestroyCond(SDL_cond * cond) +{ + if (cond) { + if (cond->wait_sem) { + SDL_DestroySemaphore(cond->wait_sem); + } + if (cond->wait_done) { + SDL_DestroySemaphore(cond->wait_done); + } + if (cond->lock) { + SDL_DestroyMutex(cond->lock); + } + SDL_free(cond); + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +int +SDL_CondSignal(SDL_cond * cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if (cond->waiting > cond->signals) { + ++cond->signals; + SDL_SemPost(cond->wait_sem); + SDL_UnlockMutex(cond->lock); + SDL_SemWait(cond->wait_done); + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +int +SDL_CondBroadcast(SDL_cond * cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if (cond->waiting > cond->signals) { + int i, num_waiting; + + num_waiting = (cond->waiting - cond->signals); + cond->signals = cond->waiting; + for (i = 0; i < num_waiting; ++i) { + SDL_SemPost(cond->wait_sem); + } + /* Now all released threads are blocked here, waiting for us. + Collect them all (and win fabulous prizes!) :-) + */ + SDL_UnlockMutex(cond->lock); + for (i = 0; i < num_waiting; ++i) { + SDL_SemWait(cond->wait_done); + } + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + SDL_LockMutex(lock); + while ( ! condition ) { + SDL_CondWait(cond, lock); + } + SDL_UnlockMutex(lock); + +Thread B: + SDL_LockMutex(lock); + ... + condition = true; + ... + SDL_CondSignal(cond); + SDL_UnlockMutex(lock); + */ +int +SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) +{ + int retval; + + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* Obtain the protection mutex, and increment the number of waiters. + This allows the signal mechanism to only perform a signal if there + are waiting threads. + */ + SDL_LockMutex(cond->lock); + ++cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Unlock the mutex, as is required by condition variable semantics */ + SDL_UnlockMutex(mutex); + + /* Wait for a signal */ + if (ms == SDL_MUTEX_MAXWAIT) { + retval = SDL_SemWait(cond->wait_sem); + } else { + retval = SDL_SemWaitTimeout(cond->wait_sem, ms); + } + + /* Let the signaler know we have completed the wait, otherwise + the signaler can race ahead and get the condition semaphore + if we are stopped between the mutex unlock and semaphore wait, + giving a deadlock. See the following URL for details: + http://web.archive.org/web/20010914175514/http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html#Workshop + */ + SDL_LockMutex(cond->lock); + if (cond->signals > 0) { + /* If we timed out, we need to eat a condition signal */ + if (retval > 0) { + SDL_SemWait(cond->wait_sem); + } + /* We always notify the signal thread that we are done */ + SDL_SemPost(cond->wait_done); + + /* Signal handshake complete */ + --cond->signals; + } + --cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Lock the mutex, as is required by condition variable semantics */ + SDL_LockMutex(mutex); + + return retval; +} + +/* Wait on the condition variable forever */ +int +SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) +{ + return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex.c b/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex.c new file mode 100644 index 0000000..df78ca9 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex.c @@ -0,0 +1,165 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* An implementation of mutexes using semaphores */ + +#include "SDL_thread.h" +#include "SDL_systhread_c.h" + + +struct SDL_mutex +{ + int recursive; + SDL_threadID owner; + SDL_sem *sem; +}; + +/* Create a mutex */ +SDL_mutex * +SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + + /* Allocate mutex memory */ + mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex)); + if (mutex) { + /* Create the mutex semaphore, with initial value 1 */ + mutex->sem = SDL_CreateSemaphore(1); + mutex->recursive = 0; + mutex->owner = 0; + if (!mutex->sem) { + SDL_free(mutex); + mutex = NULL; + } + } else { + SDL_OutOfMemory(); + } + return mutex; +} + +/* Free the mutex */ +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + if (mutex->sem) { + SDL_DestroySemaphore(mutex->sem); + } + SDL_free(mutex); + } +} + +/* Lock the mutex */ +int +SDL_LockMutex(SDL_mutex * mutex) +{ +#if SDL_THREADS_DISABLED + return 0; +#else + SDL_threadID this_thread; + + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + this_thread = SDL_ThreadID(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + SDL_SemWait(mutex->sem); + mutex->owner = this_thread; + mutex->recursive = 0; + } + + return 0; +#endif /* SDL_THREADS_DISABLED */ +} + +/* try Lock the mutex */ +int +SDL_TryLockMutex(SDL_mutex * mutex) +{ +#if SDL_THREADS_DISABLED + return 0; +#else + int retval = 0; + SDL_threadID this_thread; + + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + this_thread = SDL_ThreadID(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + retval = SDL_SemWait(mutex->sem); + if (retval == 0) { + mutex->owner = this_thread; + mutex->recursive = 0; + } + } + + return retval; +#endif /* SDL_THREADS_DISABLED */ +} + +/* Unlock the mutex */ +int +SDL_mutexV(SDL_mutex * mutex) +{ +#if SDL_THREADS_DISABLED + return 0; +#else + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + /* If we don't own the mutex, we can't unlock it */ + if (SDL_ThreadID() != mutex->owner) { + return SDL_SetError("mutex not owned by this thread"); + } + + if (mutex->recursive) { + --mutex->recursive; + } else { + /* The order of operations is important. + First reset the owner so another thread doesn't lock + the mutex and set the ownership before we reset it, + then release the lock semaphore. + */ + mutex->owner = 0; + SDL_SemPost(mutex->sem); + } + return 0; +#endif /* SDL_THREADS_DISABLED */ +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex_c.h b/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex_c.h new file mode 100644 index 0000000..2979437 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_sysmutex_c.h @@ -0,0 +1,22 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_syssem.c b/source/3rd-party/SDL2/src/thread/generic/SDL_syssem.c new file mode 100644 index 0000000..30ff824 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_syssem.c @@ -0,0 +1,217 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* An implementation of semaphores using mutexes and condition variables */ + +#include "SDL_timer.h" +#include "SDL_thread.h" +#include "SDL_systhread_c.h" + + +#if SDL_THREADS_DISABLED + +SDL_sem * +SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_SetError("SDL not built with thread support"); + return (SDL_sem *) 0; +} + +void +SDL_DestroySemaphore(SDL_sem * sem) +{ +} + +int +SDL_SemTryWait(SDL_sem * sem) +{ + return SDL_SetError("SDL not built with thread support"); +} + +int +SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) +{ + return SDL_SetError("SDL not built with thread support"); +} + +int +SDL_SemWait(SDL_sem * sem) +{ + return SDL_SetError("SDL not built with thread support"); +} + +Uint32 +SDL_SemValue(SDL_sem * sem) +{ + return 0; +} + +int +SDL_SemPost(SDL_sem * sem) +{ + return SDL_SetError("SDL not built with thread support"); +} + +#else + +struct SDL_semaphore +{ + Uint32 count; + Uint32 waiters_count; + SDL_mutex *count_lock; + SDL_cond *count_nonzero; +}; + +SDL_sem * +SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem; + + sem = (SDL_sem *) SDL_malloc(sizeof(*sem)); + if (!sem) { + SDL_OutOfMemory(); + return NULL; + } + sem->count = initial_value; + sem->waiters_count = 0; + + sem->count_lock = SDL_CreateMutex(); + sem->count_nonzero = SDL_CreateCond(); + if (!sem->count_lock || !sem->count_nonzero) { + SDL_DestroySemaphore(sem); + return NULL; + } + + return sem; +} + +/* WARNING: + You cannot call this function when another thread is using the semaphore. +*/ +void +SDL_DestroySemaphore(SDL_sem * sem) +{ + if (sem) { + sem->count = 0xFFFFFFFF; + while (sem->waiters_count > 0) { + SDL_CondSignal(sem->count_nonzero); + SDL_Delay(10); + } + SDL_DestroyCond(sem->count_nonzero); + if (sem->count_lock) { + SDL_LockMutex(sem->count_lock); + SDL_UnlockMutex(sem->count_lock); + SDL_DestroyMutex(sem->count_lock); + } + SDL_free(sem); + } +} + +int +SDL_SemTryWait(SDL_sem * sem) +{ + int retval; + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + retval = SDL_MUTEX_TIMEDOUT; + SDL_LockMutex(sem->count_lock); + if (sem->count > 0) { + --sem->count; + retval = 0; + } + SDL_UnlockMutex(sem->count_lock); + + return retval; +} + +int +SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) +{ + int retval; + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + /* A timeout of 0 is an easy case */ + if (timeout == 0) { + return SDL_SemTryWait(sem); + } + + SDL_LockMutex(sem->count_lock); + ++sem->waiters_count; + retval = 0; + while ((sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT)) { + retval = SDL_CondWaitTimeout(sem->count_nonzero, + sem->count_lock, timeout); + } + --sem->waiters_count; + if (retval == 0) { + --sem->count; + } + SDL_UnlockMutex(sem->count_lock); + + return retval; +} + +int +SDL_SemWait(SDL_sem * sem) +{ + return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); +} + +Uint32 +SDL_SemValue(SDL_sem * sem) +{ + Uint32 value; + + value = 0; + if (sem) { + SDL_LockMutex(sem->count_lock); + value = sem->count; + SDL_UnlockMutex(sem->count_lock); + } + return value; +} + +int +SDL_SemPost(SDL_sem * sem) +{ + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + SDL_LockMutex(sem->count_lock); + if (sem->waiters_count > 0) { + SDL_CondSignal(sem->count_nonzero); + } + ++sem->count; + SDL_UnlockMutex(sem->count_lock); + + return 0; +} + +#endif /* SDL_THREADS_DISABLED */ +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_systhread.c b/source/3rd-party/SDL2/src/thread/generic/SDL_systhread.c new file mode 100644 index 0000000..7a19b78 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_systhread.c @@ -0,0 +1,71 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* Thread management routines for SDL */ + +#include "SDL_thread.h" +#include "../SDL_systhread.h" + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread) +#else +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args) +#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ +{ + return SDL_SetError("Threads are not supported on this platform"); +} + +void +SDL_SYS_SetupThread(const char *name) +{ + return; +} + +SDL_threadID +SDL_ThreadID(void) +{ + return (0); +} + +int +SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + return (0); +} + +void +SDL_SYS_WaitThread(SDL_Thread * thread) +{ + return; +} + +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + return; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_systhread_c.h b/source/3rd-party/SDL2/src/thread/generic/SDL_systhread_c.h new file mode 100644 index 0000000..13db579 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_systhread_c.h @@ -0,0 +1,26 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* Stub until we implement threads on this platform */ +typedef int SYS_ThreadHandle; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/generic/SDL_systls.c b/source/3rd-party/SDL2/src/thread/generic/SDL_systls.c new file mode 100644 index 0000000..241862e --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/generic/SDL_systls.c @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" +#include "../SDL_thread_c.h" + + +SDL_TLSData * +SDL_SYS_GetTLSData(void) +{ + return SDL_Generic_GetTLSData(); +} + +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + return SDL_Generic_SetTLSData(data); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_syscond.c b/source/3rd-party/SDL2/src/thread/psp/SDL_syscond.c new file mode 100644 index 0000000..4ed73e0 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_syscond.c @@ -0,0 +1,224 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_PSP + +/* An implementation of condition variables using semaphores and mutexes */ +/* + This implementation borrows heavily from the BeOS condition variable + implementation, written by Christopher Tate and Owen Smith. Thanks! + */ + +#include "SDL_thread.h" + +struct SDL_cond +{ + SDL_mutex *lock; + int waiting; + int signals; + SDL_sem *wait_sem; + SDL_sem *wait_done; +}; + +/* Create a condition variable */ +SDL_cond * +SDL_CreateCond(void) +{ + SDL_cond *cond; + + cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); + if (cond) { + cond->lock = SDL_CreateMutex(); + cond->wait_sem = SDL_CreateSemaphore(0); + cond->wait_done = SDL_CreateSemaphore(0); + cond->waiting = cond->signals = 0; + if (!cond->lock || !cond->wait_sem || !cond->wait_done) { + SDL_DestroyCond(cond); + cond = NULL; + } + } else { + SDL_OutOfMemory(); + } + return (cond); +} + +/* Destroy a condition variable */ +void +SDL_DestroyCond(SDL_cond * cond) +{ + if (cond) { + if (cond->wait_sem) { + SDL_DestroySemaphore(cond->wait_sem); + } + if (cond->wait_done) { + SDL_DestroySemaphore(cond->wait_done); + } + if (cond->lock) { + SDL_DestroyMutex(cond->lock); + } + SDL_free(cond); + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +int +SDL_CondSignal(SDL_cond * cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if (cond->waiting > cond->signals) { + ++cond->signals; + SDL_SemPost(cond->wait_sem); + SDL_UnlockMutex(cond->lock); + SDL_SemWait(cond->wait_done); + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +int +SDL_CondBroadcast(SDL_cond * cond) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if (cond->waiting > cond->signals) { + int i, num_waiting; + + num_waiting = (cond->waiting - cond->signals); + cond->signals = cond->waiting; + for (i = 0; i < num_waiting; ++i) { + SDL_SemPost(cond->wait_sem); + } + /* Now all released threads are blocked here, waiting for us. + Collect them all (and win fabulous prizes!) :-) + */ + SDL_UnlockMutex(cond->lock); + for (i = 0; i < num_waiting; ++i) { + SDL_SemWait(cond->wait_done); + } + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + SDL_LockMutex(lock); + while ( ! condition ) { + SDL_CondWait(cond, lock); + } + SDL_UnlockMutex(lock); + +Thread B: + SDL_LockMutex(lock); + ... + condition = true; + ... + SDL_CondSignal(cond); + SDL_UnlockMutex(lock); + */ +int +SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) +{ + int retval; + + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + /* Obtain the protection mutex, and increment the number of waiters. + This allows the signal mechanism to only perform a signal if there + are waiting threads. + */ + SDL_LockMutex(cond->lock); + ++cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Unlock the mutex, as is required by condition variable semantics */ + SDL_UnlockMutex(mutex); + + /* Wait for a signal */ + if (ms == SDL_MUTEX_MAXWAIT) { + retval = SDL_SemWait(cond->wait_sem); + } else { + retval = SDL_SemWaitTimeout(cond->wait_sem, ms); + } + + /* Let the signaler know we have completed the wait, otherwise + the signaler can race ahead and get the condition semaphore + if we are stopped between the mutex unlock and semaphore wait, + giving a deadlock. See the following URL for details: + http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html + */ + SDL_LockMutex(cond->lock); + if (cond->signals > 0) { + /* If we timed out, we need to eat a condition signal */ + if (retval > 0) { + SDL_SemWait(cond->wait_sem); + } + /* We always notify the signal thread that we are done */ + SDL_SemPost(cond->wait_done); + + /* Signal handshake complete */ + --cond->signals; + } + --cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Lock the mutex, as is required by condition variable semantics */ + SDL_LockMutex(mutex); + + return retval; +} + +/* Wait on the condition variable forever */ +int +SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) +{ + return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); +} + +#endif /* SDL_THREAD_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex.c b/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex.c new file mode 100644 index 0000000..e2db5eb --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex.c @@ -0,0 +1,136 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_PSP + +/* An implementation of mutexes using semaphores */ + +#include "SDL_thread.h" +#include "SDL_systhread_c.h" + + +struct SDL_mutex +{ + int recursive; + SDL_threadID owner; + SDL_sem *sem; +}; + +/* Create a mutex */ +SDL_mutex * +SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + + /* Allocate mutex memory */ + mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex)); + if (mutex) { + /* Create the mutex semaphore, with initial value 1 */ + mutex->sem = SDL_CreateSemaphore(1); + mutex->recursive = 0; + mutex->owner = 0; + if (!mutex->sem) { + SDL_free(mutex); + mutex = NULL; + } + } else { + SDL_OutOfMemory(); + } + return mutex; +} + +/* Free the mutex */ +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + if (mutex->sem) { + SDL_DestroySemaphore(mutex->sem); + } + SDL_free(mutex); + } +} + +/* Lock the semaphore */ +int +SDL_mutexP(SDL_mutex * mutex) +{ +#if SDL_THREADS_DISABLED + return 0; +#else + SDL_threadID this_thread; + + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + this_thread = SDL_ThreadID(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + SDL_SemWait(mutex->sem); + mutex->owner = this_thread; + mutex->recursive = 0; + } + + return 0; +#endif /* SDL_THREADS_DISABLED */ +} + +/* Unlock the mutex */ +int +SDL_mutexV(SDL_mutex * mutex) +{ +#if SDL_THREADS_DISABLED + return 0; +#else + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + /* If we don't own the mutex, we can't unlock it */ + if (SDL_ThreadID() != mutex->owner) { + return SDL_SetError("mutex not owned by this thread"); + } + + if (mutex->recursive) { + --mutex->recursive; + } else { + /* The order of operations is important. + First reset the owner so another thread doesn't lock + the mutex and set the ownership before we reset it, + then release the lock semaphore. + */ + mutex->owner = 0; + SDL_SemPost(mutex->sem); + } + return 0; +#endif /* SDL_THREADS_DISABLED */ +} + +#endif /* SDL_THREAD_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex_c.h b/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex_c.h new file mode 100644 index 0000000..2979437 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_sysmutex_c.h @@ -0,0 +1,22 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_syssem.c b/source/3rd-party/SDL2/src/thread/psp/SDL_syssem.c new file mode 100644 index 0000000..0c36434 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_syssem.c @@ -0,0 +1,161 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_PSP + +/* Semaphore functions for the PSP. */ + +#include <stdio.h> +#include <stdlib.h> + +#include "SDL_error.h" +#include "SDL_thread.h" + +#include <pspthreadman.h> +#include <pspkerror.h> + +struct SDL_semaphore { + SceUID semid; +}; + + +/* Create a semaphore */ +SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem; + + sem = (SDL_sem *) malloc(sizeof(*sem)); + if (sem != NULL) { + /* TODO: Figure out the limit on the maximum value. */ + sem->semid = sceKernelCreateSema("SDL sema", 0, initial_value, 255, NULL); + if (sem->semid < 0) { + SDL_SetError("Couldn't create semaphore"); + free(sem); + sem = NULL; + } + } else { + SDL_OutOfMemory(); + } + + return sem; +} + +/* Free the semaphore */ +void SDL_DestroySemaphore(SDL_sem *sem) +{ + if (sem != NULL) { + if (sem->semid > 0) { + sceKernelDeleteSema(sem->semid); + sem->semid = 0; + } + + free(sem); + } +} + +/* TODO: This routine is a bit overloaded. + * If the timeout is 0 then just poll the semaphore; if it's SDL_MUTEX_MAXWAIT, pass + * NULL to sceKernelWaitSema() so that it waits indefinitely; and if the timeout + * is specified, convert it to microseconds. */ +int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) +{ + Uint32 *pTimeout; + int res; + + if (sem == NULL) { + SDL_SetError("Passed a NULL sem"); + return 0; + } + + if (timeout == 0) { + res = sceKernelPollSema(sem->semid, 1); + if (res < 0) { + return SDL_MUTEX_TIMEDOUT; + } + return 0; + } + + if (timeout == SDL_MUTEX_MAXWAIT) { + pTimeout = NULL; + } else { + timeout *= 1000; /* Convert to microseconds. */ + pTimeout = &timeout; + } + + res = sceKernelWaitSema(sem->semid, 1, pTimeout); + switch (res) { + case SCE_KERNEL_ERROR_OK: + return 0; + case SCE_KERNEL_ERROR_WAIT_TIMEOUT: + return SDL_MUTEX_TIMEDOUT; + default: + return SDL_SetError("sceKernelWaitSema() failed"); + } +} + +int SDL_SemTryWait(SDL_sem *sem) +{ + return SDL_SemWaitTimeout(sem, 0); +} + +int SDL_SemWait(SDL_sem *sem) +{ + return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +Uint32 SDL_SemValue(SDL_sem *sem) +{ + SceKernelSemaInfo info; + + if (sem == NULL) { + SDL_SetError("Passed a NULL sem"); + return 0; + } + + if (sceKernelReferSemaStatus(sem->semid, &info) >= 0) { + return info.currentCount; + } + + return 0; +} + +int SDL_SemPost(SDL_sem *sem) +{ + int res; + + if (sem == NULL) { + return SDL_SetError("Passed a NULL sem"); + } + + res = sceKernelSignalSema(sem->semid, 1); + if (res < 0) { + return SDL_SetError("sceKernelSignalSema() failed"); + } + + return 0; +} + +#endif /* SDL_THREAD_PSP */ + +/* vim: ts=4 sw=4 + */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_systhread.c b/source/3rd-party/SDL2/src/thread/psp/SDL_systhread.c new file mode 100644 index 0000000..284f182 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_systhread.c @@ -0,0 +1,114 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_PSP + +/* PSP thread management routines for SDL */ + +#include <stdio.h> +#include <stdlib.h> + +#include "SDL_error.h" +#include "SDL_thread.h" +#include "../SDL_systhread.h" +#include "../SDL_thread_c.h" +#include <pspkerneltypes.h> +#include <pspthreadman.h> + + +static int ThreadEntry(SceSize args, void *argp) +{ + SDL_RunThread(*(void **) argp); + return 0; +} + +int SDL_SYS_CreateThread(SDL_Thread *thread, void *args) +{ + SceKernelThreadInfo status; + int priority = 32; + + /* Set priority of new thread to the same as the current thread */ + status.size = sizeof(SceKernelThreadInfo); + if (sceKernelReferThreadStatus(sceKernelGetThreadId(), &status) == 0) { + priority = status.currentPriority; + } + + thread->handle = sceKernelCreateThread(thread->name, ThreadEntry, + priority, thread->stacksize ? ((int) thread->stacksize) : 0x8000, + PSP_THREAD_ATTR_VFPU, NULL); + if (thread->handle < 0) { + return SDL_SetError("sceKernelCreateThread() failed"); + } + + sceKernelStartThread(thread->handle, 4, &args); + return 0; +} + +void SDL_SYS_SetupThread(const char *name) +{ + /* Do nothing. */ +} + +SDL_threadID SDL_ThreadID(void) +{ + return (SDL_threadID) sceKernelGetThreadId(); +} + +void SDL_SYS_WaitThread(SDL_Thread *thread) +{ + sceKernelWaitThreadEnd(thread->handle, NULL); + sceKernelDeleteThread(thread->handle); +} + +void SDL_SYS_DetachThread(SDL_Thread *thread) +{ + /* !!! FIXME: is this correct? */ + sceKernelDeleteThread(thread->handle); +} + +void SDL_SYS_KillThread(SDL_Thread *thread) +{ + sceKernelTerminateDeleteThread(thread->handle); +} + +int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + int value; + + if (priority == SDL_THREAD_PRIORITY_LOW) { + value = 19; + } else if (priority == SDL_THREAD_PRIORITY_HIGH) { + value = -10; + } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { + value = -20; + } else { + value = 0; + } + + return sceKernelChangeThreadPriority(sceKernelGetThreadId(),value); + +} + +#endif /* SDL_THREAD_PSP */ + +/* vim: ts=4 sw=4 + */ diff --git a/source/3rd-party/SDL2/src/thread/psp/SDL_systhread_c.h b/source/3rd-party/SDL2/src/thread/psp/SDL_systhread_c.h new file mode 100644 index 0000000..ea26f81 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/psp/SDL_systhread_c.h @@ -0,0 +1,24 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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 <pspkerneltypes.h> + +typedef SceUID SYS_ThreadHandle; diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_syscond.c b/source/3rd-party/SDL2/src/thread/pthread/SDL_syscond.c new file mode 100644 index 0000000..d235780 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_syscond.c @@ -0,0 +1,158 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> + +#include "SDL_thread.h" +#include "SDL_sysmutex_c.h" + +struct SDL_cond +{ + pthread_cond_t cond; +}; + +/* Create a condition variable */ +SDL_cond * +SDL_CreateCond(void) +{ + SDL_cond *cond; + + cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); + if (cond) { + if (pthread_cond_init(&cond->cond, NULL) != 0) { + SDL_SetError("pthread_cond_init() failed"); + SDL_free(cond); + cond = NULL; + } + } + return (cond); +} + +/* Destroy a condition variable */ +void +SDL_DestroyCond(SDL_cond * cond) +{ + if (cond) { + pthread_cond_destroy(&cond->cond); + SDL_free(cond); + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +int +SDL_CondSignal(SDL_cond * cond) +{ + int retval; + + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + retval = 0; + if (pthread_cond_signal(&cond->cond) != 0) { + return SDL_SetError("pthread_cond_signal() failed"); + } + return retval; +} + +/* Restart all threads that are waiting on the condition variable */ +int +SDL_CondBroadcast(SDL_cond * cond) +{ + int retval; + + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + + retval = 0; + if (pthread_cond_broadcast(&cond->cond) != 0) { + return SDL_SetError("pthread_cond_broadcast() failed"); + } + return retval; +} + +int +SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) +{ + int retval; +#ifndef HAVE_CLOCK_GETTIME + struct timeval delta; +#endif + struct timespec abstime; + + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } + +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &abstime); + + abstime.tv_nsec += (ms % 1000) * 1000000; + abstime.tv_sec += ms / 1000; +#else + gettimeofday(&delta, NULL); + + abstime.tv_sec = delta.tv_sec + (ms / 1000); + abstime.tv_nsec = (delta.tv_usec + (ms % 1000) * 1000) * 1000; +#endif + if (abstime.tv_nsec > 1000000000) { + abstime.tv_sec += 1; + abstime.tv_nsec -= 1000000000; + } + + tryagain: + retval = pthread_cond_timedwait(&cond->cond, &mutex->id, &abstime); + switch (retval) { + case EINTR: + goto tryagain; + /* break; -Wunreachable-code-break */ + case ETIMEDOUT: + retval = SDL_MUTEX_TIMEDOUT; + break; + case 0: + break; + default: + retval = SDL_SetError("pthread_cond_timedwait() failed"); + } + return retval; +} + +/* Wait on the condition variable, unlocking the provided mutex. + The mutex must be locked before entering this function! + */ +int +SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) +{ + if (!cond) { + return SDL_SetError("Passed a NULL condition variable"); + } else if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) { + return SDL_SetError("pthread_cond_wait() failed"); + } + return 0; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex.c b/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex.c new file mode 100644 index 0000000..e514778 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex.c @@ -0,0 +1,195 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#include <errno.h> +#include <pthread.h> + +#include "SDL_thread.h" + +#if !SDL_THREAD_PTHREAD_RECURSIVE_MUTEX && \ + !SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP +#define FAKE_RECURSIVE_MUTEX 1 +#endif + +struct SDL_mutex +{ + pthread_mutex_t id; +#if FAKE_RECURSIVE_MUTEX + int recursive; + pthread_t owner; +#endif +}; + +SDL_mutex * +SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + pthread_mutexattr_t attr; + + /* Allocate the structure */ + mutex = (SDL_mutex *) SDL_calloc(1, sizeof(*mutex)); + if (mutex) { + pthread_mutexattr_init(&attr); +#if SDL_THREAD_PTHREAD_RECURSIVE_MUTEX + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#elif SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP + pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP); +#else + /* No extra attributes necessary */ +#endif + if (pthread_mutex_init(&mutex->id, &attr) != 0) { + SDL_SetError("pthread_mutex_init() failed"); + SDL_free(mutex); + mutex = NULL; + } + } else { + SDL_OutOfMemory(); + } + return (mutex); +} + +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + pthread_mutex_destroy(&mutex->id); + SDL_free(mutex); + } +} + +/* Lock the mutex */ +int +SDL_LockMutex(SDL_mutex * mutex) +{ +#if FAKE_RECURSIVE_MUTEX + pthread_t this_thread; +#endif + + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + +#if FAKE_RECURSIVE_MUTEX + this_thread = pthread_self(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + if (pthread_mutex_lock(&mutex->id) == 0) { + mutex->owner = this_thread; + mutex->recursive = 0; + } else { + return SDL_SetError("pthread_mutex_lock() failed"); + } + } +#else + if (pthread_mutex_lock(&mutex->id) != 0) { + return SDL_SetError("pthread_mutex_lock() failed"); + } +#endif + return 0; +} + +int +SDL_TryLockMutex(SDL_mutex * mutex) +{ + int retval; + int result; +#if FAKE_RECURSIVE_MUTEX + pthread_t this_thread; +#endif + + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + retval = 0; +#if FAKE_RECURSIVE_MUTEX + this_thread = pthread_self(); + if (mutex->owner == this_thread) { + ++mutex->recursive; + } else { + /* The order of operations is important. + We set the locking thread id after we obtain the lock + so unlocks from other threads will fail. + */ + result = pthread_mutex_trylock(&mutex->id); + if (result == 0) { + mutex->owner = this_thread; + mutex->recursive = 0; + } else if (result == EBUSY) { + retval = SDL_MUTEX_TIMEDOUT; + } else { + retval = SDL_SetError("pthread_mutex_trylock() failed"); + } + } +#else + result = pthread_mutex_trylock(&mutex->id); + if (result != 0) { + if (result == EBUSY) { + retval = SDL_MUTEX_TIMEDOUT; + } else { + retval = SDL_SetError("pthread_mutex_trylock() failed"); + } + } +#endif + return retval; +} + +int +SDL_UnlockMutex(SDL_mutex * mutex) +{ + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + +#if FAKE_RECURSIVE_MUTEX + /* We can only unlock the mutex if we own it */ + if (pthread_self() == mutex->owner) { + if (mutex->recursive) { + --mutex->recursive; + } else { + /* The order of operations is important. + First reset the owner so another thread doesn't lock + the mutex and set the ownership before we reset it, + then release the lock semaphore. + */ + mutex->owner = 0; + pthread_mutex_unlock(&mutex->id); + } + } else { + return SDL_SetError("mutex not owned by this thread"); + } + +#else + if (pthread_mutex_unlock(&mutex->id) != 0) { + return SDL_SetError("pthread_mutex_unlock() failed"); + } +#endif /* FAKE_RECURSIVE_MUTEX */ + + return 0; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex_c.h b/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex_c.h new file mode 100644 index 0000000..27ac1da --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_sysmutex_c.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#ifndef SDL_mutex_c_h_ +#define SDL_mutex_c_h_ + +struct SDL_mutex +{ + pthread_mutex_t id; +}; + +#endif /* SDL_mutex_c_h_ */ +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_syssem.c b/source/3rd-party/SDL2/src/thread/pthread/SDL_syssem.c new file mode 100644 index 0000000..bdebf13 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_syssem.c @@ -0,0 +1,209 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <sys/time.h> +#include <time.h> + +#include "SDL_thread.h" +#include "SDL_timer.h" + +/* Wrapper around POSIX 1003.1b semaphores */ + +#if defined(__MACOSX__) || defined(__IPHONEOS__) +/* Mac OS X doesn't support sem_getvalue() as of version 10.4 */ +#include "../generic/SDL_syssem.c" +#else + +struct SDL_semaphore +{ + sem_t sem; +}; + +/* Create a semaphore, initialized with value */ +SDL_sem * +SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem)); + if (sem) { + if (sem_init(&sem->sem, 0, initial_value) < 0) { + SDL_SetError("sem_init() failed"); + SDL_free(sem); + sem = NULL; + } + } else { + SDL_OutOfMemory(); + } + return sem; +} + +void +SDL_DestroySemaphore(SDL_sem * sem) +{ + if (sem) { + sem_destroy(&sem->sem); + SDL_free(sem); + } +} + +int +SDL_SemTryWait(SDL_sem * sem) +{ + int retval; + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + retval = SDL_MUTEX_TIMEDOUT; + if (sem_trywait(&sem->sem) == 0) { + retval = 0; + } + return retval; +} + +int +SDL_SemWait(SDL_sem * sem) +{ + int retval; + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + do { + retval = sem_wait(&sem->sem); + } while (retval < 0 && errno == EINTR); + + if (retval < 0) { + retval = SDL_SetError("sem_wait() failed"); + } + return retval; +} + +int +SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) +{ + int retval; +#ifdef HAVE_SEM_TIMEDWAIT +#ifndef HAVE_CLOCK_GETTIME + struct timeval now; +#endif + struct timespec ts_timeout; +#else + Uint32 end; +#endif + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + /* Try the easy cases first */ + if (timeout == 0) { + return SDL_SemTryWait(sem); + } + if (timeout == SDL_MUTEX_MAXWAIT) { + return SDL_SemWait(sem); + } + +#ifdef HAVE_SEM_TIMEDWAIT + /* Setup the timeout. sem_timedwait doesn't wait for + * a lapse of time, but until we reach a certain time. + * This time is now plus the timeout. + */ +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &ts_timeout); + + /* Add our timeout to current time */ + ts_timeout.tv_nsec += (timeout % 1000) * 1000000; + ts_timeout.tv_sec += timeout / 1000; +#else + gettimeofday(&now, NULL); + + /* Add our timeout to current time */ + ts_timeout.tv_sec = now.tv_sec + (timeout / 1000); + ts_timeout.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000; +#endif + + /* Wrap the second if needed */ + if (ts_timeout.tv_nsec > 1000000000) { + ts_timeout.tv_sec += 1; + ts_timeout.tv_nsec -= 1000000000; + } + + /* Wait. */ + do { + retval = sem_timedwait(&sem->sem, &ts_timeout); + } while (retval < 0 && errno == EINTR); + + if (retval < 0) { + if (errno == ETIMEDOUT) { + retval = SDL_MUTEX_TIMEDOUT; + } else { + SDL_SetError("sem_timedwait returned an error: %s", strerror(errno)); + } + } +#else + end = SDL_GetTicks() + timeout; + while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) { + if (SDL_TICKS_PASSED(SDL_GetTicks(), end)) { + break; + } + SDL_Delay(1); + } +#endif /* HAVE_SEM_TIMEDWAIT */ + + return retval; +} + +Uint32 +SDL_SemValue(SDL_sem * sem) +{ + int ret = 0; + if (sem) { + sem_getvalue(&sem->sem, &ret); + if (ret < 0) { + ret = 0; + } + } + return (Uint32) ret; +} + +int +SDL_SemPost(SDL_sem * sem) +{ + int retval; + + if (!sem) { + return SDL_SetError("Passed a NULL semaphore"); + } + + retval = sem_post(&sem->sem); + if (retval < 0) { + SDL_SetError("sem_post() failed"); + } + return retval; +} + +#endif /* __MACOSX__ */ +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread.c b/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread.c new file mode 100644 index 0000000..ec32937 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread.c @@ -0,0 +1,324 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#include <pthread.h> + +#if HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif + +#include <signal.h> + +#ifdef __LINUX__ +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <errno.h> + +#include "../../core/linux/SDL_dbus.h" +#endif /* __LINUX__ */ + +#if defined(__LINUX__) || defined(__MACOSX__) || defined(__IPHONEOS__) +#include <dlfcn.h> +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT NULL +#endif +#endif + +#include "SDL_log.h" +#include "SDL_platform.h" +#include "SDL_thread.h" +#include "../SDL_thread_c.h" +#include "../SDL_systhread.h" +#ifdef __ANDROID__ +#include "../../core/android/SDL_android.h" +#endif + +#ifdef __HAIKU__ +#include <kernel/OS.h> +#endif + +#include "SDL_assert.h" + +#ifndef __NACL__ +/* List of signals to mask in the subthreads */ +static const int sig_list[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH, + SIGVTALRM, SIGPROF, 0 +}; +#endif + +static void * +RunThread(void *data) +{ +#ifdef __ANDROID__ + Android_JNI_SetupThread(); +#endif + SDL_RunThread(data); + return NULL; +} + +#if defined(__MACOSX__) || defined(__IPHONEOS__) +static SDL_bool checked_setname = SDL_FALSE; +static int (*ppthread_setname_np)(const char*) = NULL; +#elif defined(__LINUX__) +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, void *args) +{ + pthread_attr_t type; + + /* do this here before any threads exist, so there's no race condition. */ + #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__) + if (!checked_setname) { + void *fn = dlsym(RTLD_DEFAULT, "pthread_setname_np"); + #if defined(__MACOSX__) || defined(__IPHONEOS__) + ppthread_setname_np = (int(*)(const char*)) fn; + #elif defined(__LINUX__) + ppthread_setname_np = (int(*)(pthread_t, const char*)) fn; + #endif + checked_setname = SDL_TRUE; + } + #endif + + /* Set the thread attributes */ + if (pthread_attr_init(&type) != 0) { + return SDL_SetError("Couldn't initialize pthread attributes"); + } + pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE); + + /* Set caller-requested stack size. Otherwise: use the system default. */ + if (thread->stacksize) { + pthread_attr_setstacksize(&type, (size_t) thread->stacksize); + } + + /* Create the thread and go! */ + if (pthread_create(&thread->handle, &type, RunThread, args) != 0) { + return SDL_SetError("Not enough resources to create thread"); + } + + return 0; +} + +void +SDL_SYS_SetupThread(const char *name) +{ +#if !defined(__NACL__) + int i; + sigset_t mask; +#endif /* !__NACL__ */ + + if (name != NULL) { + #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__) + SDL_assert(checked_setname); + if (ppthread_setname_np != NULL) { + #if defined(__MACOSX__) || defined(__IPHONEOS__) + ppthread_setname_np(name); + #elif defined(__LINUX__) + ppthread_setname_np(pthread_self(), name); + #endif + } + #elif HAVE_PTHREAD_SETNAME_NP + #if defined(__NETBSD__) + pthread_setname_np(pthread_self(), "%s", name); + #else + pthread_setname_np(pthread_self(), name); + #endif + #elif HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(pthread_self(), name); + #elif defined(__HAIKU__) + /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */ + char namebuf[B_OS_NAME_LENGTH]; + SDL_snprintf(namebuf, sizeof (namebuf), "%s", name); + namebuf[sizeof (namebuf) - 1] = '\0'; + rename_thread(find_thread(NULL), namebuf); + #endif + } + + /* NativeClient does not yet support signals.*/ +#if !defined(__NACL__) + /* Mask asynchronous signals for this thread */ + sigemptyset(&mask); + for (i = 0; sig_list[i]; ++i) { + sigaddset(&mask, sig_list[i]); + } + pthread_sigmask(SIG_BLOCK, &mask, 0); +#endif /* !__NACL__ */ + + +#ifdef PTHREAD_CANCEL_ASYNCHRONOUS + /* Allow ourselves to be asynchronously cancelled */ + { + int oldstate; + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate); + } +#endif +} + +SDL_threadID +SDL_ThreadID(void) +{ + return ((SDL_threadID) pthread_self()); +} + +#if __LINUX__ +/* d-bus queries to org.freedesktop.RealtimeKit1. */ +#if SDL_USE_LIBDBUS + +#define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1" +#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1" +#define RTKIT_DBUS_INTERFACE "org.freedesktop.RealtimeKit1" + +static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT; +static Sint32 rtkit_min_nice_level = -20; + +static void +rtkit_initialize() +{ + SDL_DBusContext *dbus = SDL_DBus_GetContext(); + + /* Try getting minimum nice level: this is often greater than PRIO_MIN (-20). */ + if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MinNiceLevel", + DBUS_TYPE_INT32, &rtkit_min_nice_level)) { + rtkit_min_nice_level = -20; + } +} + +static SDL_bool +rtkit_setpriority(pid_t thread, int nice_level) +{ + Uint64 ui64 = (Uint64)thread; + Sint32 si32 = (Sint32)nice_level; + SDL_DBusContext *dbus = SDL_DBus_GetContext(); + + pthread_once(&rtkit_initialize_once, rtkit_initialize); + + if (si32 < rtkit_min_nice_level) + si32 = rtkit_min_nice_level; + + if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn, + RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority", + DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID, + DBUS_TYPE_INVALID)) { + return SDL_FALSE; + } + return SDL_TRUE; +} + +#else + +static SDL_bool +rtkit_setpriority(pid_t thread, int nice_level) +{ + return SDL_FALSE; +} + +#endif /* !SDL_USE_LIBDBUS */ + +int +SDL_LinuxSetThreadPriority(Sint64 threadID, int priority) +{ + if (setpriority(PRIO_PROCESS, (id_t)threadID, priority) < 0) { + /* Note that this fails if you're trying to set high priority + and you don't have root permission. BUT DON'T RUN AS ROOT! + + You can grant the ability to increase thread priority by + running the following command on your application binary: + sudo setcap 'cap_sys_nice=eip' <application> + + Let's try setting priority with RealtimeKit... + + README and sample code at: + http://git.0pointer.net/rtkit.git + */ + if (rtkit_setpriority((pid_t)threadID, priority) == SDL_FALSE) { + return SDL_SetError("setpriority() failed"); + } + } + return 0; +} +#endif /* __LINUX__ */ + +int +SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ +#if __NACL__ + /* FIXME: Setting thread priority does not seem to be supported in NACL */ + return 0; +#elif __LINUX__ + int value; + pid_t thread = syscall(SYS_gettid); + + if (priority == SDL_THREAD_PRIORITY_LOW) { + value = 19; + } else if (priority == SDL_THREAD_PRIORITY_HIGH) { + value = -10; + } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { + value = -20; + } else { + value = 0; + } + return SDL_LinuxSetThreadPriority(thread, value); +#else + struct sched_param sched; + int policy; + pthread_t thread = pthread_self(); + + if (pthread_getschedparam(thread, &policy, &sched) != 0) { + return SDL_SetError("pthread_getschedparam() failed"); + } + if (priority == SDL_THREAD_PRIORITY_LOW) { + sched.sched_priority = sched_get_priority_min(policy); + } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { + sched.sched_priority = sched_get_priority_max(policy); + } else { + int min_priority = sched_get_priority_min(policy); + int max_priority = sched_get_priority_max(policy); + sched.sched_priority = (min_priority + (max_priority - min_priority) / 2); + if (priority == SDL_THREAD_PRIORITY_HIGH) { + sched.sched_priority += ((max_priority - min_priority) / 4); + } + } + if (pthread_setschedparam(thread, policy, &sched) != 0) { + return SDL_SetError("pthread_setschedparam() failed"); + } + return 0; +#endif /* linux */ +} + +void +SDL_SYS_WaitThread(SDL_Thread * thread) +{ + pthread_join(thread->handle, 0); +} + +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + pthread_detach(thread->handle); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread_c.h b/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread_c.h new file mode 100644 index 0000000..898c219 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_systhread_c.h @@ -0,0 +1,27 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#include <pthread.h> + +typedef pthread_t SYS_ThreadHandle; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/pthread/SDL_systls.c b/source/3rd-party/SDL2/src/thread/pthread/SDL_systls.c new file mode 100644 index 0000000..c580595 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/pthread/SDL_systls.c @@ -0,0 +1,70 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" +#include "SDL_thread.h" +#include "../SDL_systhread.h" +#include "../SDL_thread_c.h" + +#include <pthread.h> + + +#define INVALID_PTHREAD_KEY ((pthread_key_t)-1) + +static pthread_key_t thread_local_storage = INVALID_PTHREAD_KEY; +static SDL_bool generic_local_storage = SDL_FALSE; + +SDL_TLSData * +SDL_SYS_GetTLSData(void) +{ + if (thread_local_storage == INVALID_PTHREAD_KEY && !generic_local_storage) { + static SDL_SpinLock lock; + SDL_AtomicLock(&lock); + if (thread_local_storage == INVALID_PTHREAD_KEY && !generic_local_storage) { + pthread_key_t storage; + if (pthread_key_create(&storage, NULL) == 0) { + SDL_MemoryBarrierRelease(); + thread_local_storage = storage; + } else { + generic_local_storage = SDL_TRUE; + } + } + SDL_AtomicUnlock(&lock); + } + if (generic_local_storage) { + return SDL_Generic_GetTLSData(); + } + SDL_MemoryBarrierAcquire(); + return (SDL_TLSData *)pthread_getspecific(thread_local_storage); +} + +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + if (generic_local_storage) { + return SDL_Generic_SetTLSData(data); + } + if (pthread_setspecific(thread_local_storage, data) != 0) { + return SDL_SetError("pthread_setspecific() failed"); + } + return 0; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/stdcpp/SDL_syscond.cpp b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_syscond.cpp new file mode 100644 index 0000000..32c7c4b --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_syscond.cpp @@ -0,0 +1,164 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +extern "C" { +#include "SDL_thread.h" +} + +#include <chrono> +#include <condition_variable> +#include <ratio> +#include <system_error> + +#include "SDL_sysmutex_c.h" + +struct SDL_cond +{ + std::condition_variable_any cpp_cond; +}; + +/* Create a condition variable */ +extern "C" +SDL_cond * +SDL_CreateCond(void) +{ + /* Allocate and initialize the condition variable */ + try { + SDL_cond * cond = new SDL_cond; + return cond; + } catch (std::system_error & ex) { + SDL_SetError("unable to create a C++ condition variable: code=%d; %s", ex.code(), ex.what()); + return NULL; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + return NULL; + } +} + +/* Destroy a condition variable */ +extern "C" +void +SDL_DestroyCond(SDL_cond * cond) +{ + if (cond) { + delete cond; + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +extern "C" +int +SDL_CondSignal(SDL_cond * cond) +{ + if (!cond) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + cond->cpp_cond.notify_one(); + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +extern "C" +int +SDL_CondBroadcast(SDL_cond * cond) +{ + if (!cond) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + cond->cpp_cond.notify_all(); + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + SDL_LockMutex(lock); + while ( ! condition ) { + SDL_CondWait(cond, lock); + } + SDL_UnlockMutex(lock); + +Thread B: + SDL_LockMutex(lock); + ... + condition = true; + ... + SDL_CondSignal(cond); + SDL_UnlockMutex(lock); + */ +extern "C" +int +SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) +{ + if (!cond) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + if (!mutex) { + SDL_SetError("Passed a NULL mutex variable"); + return -1; + } + + try { + std::unique_lock<std::recursive_mutex> cpp_lock(mutex->cpp_mutex, std::adopt_lock_t()); + if (ms == SDL_MUTEX_MAXWAIT) { + cond->cpp_cond.wait( + cpp_lock + ); + cpp_lock.release(); + return 0; + } else { + auto wait_result = cond->cpp_cond.wait_for( + cpp_lock, + std::chrono::duration<Uint32, std::milli>(ms) + ); + cpp_lock.release(); + if (wait_result == std::cv_status::timeout) { + return SDL_MUTEX_TIMEDOUT; + } else { + return 0; + } + } + } catch (std::system_error & ex) { + SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what()); + return -1; + } +} + +/* Wait on the condition variable forever */ +extern "C" +int +SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) +{ + return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex.cpp b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex.cpp new file mode 100644 index 0000000..667d36b --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex.cpp @@ -0,0 +1,111 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +extern "C" { +#include "SDL_thread.h" +#include "SDL_systhread_c.h" +#include "SDL_log.h" +} + +#include <system_error> + +#include "SDL_sysmutex_c.h" +#include <Windows.h> + + +/* Create a mutex */ +extern "C" +SDL_mutex * +SDL_CreateMutex(void) +{ + /* Allocate and initialize the mutex */ + try { + SDL_mutex * mutex = new SDL_mutex; + return mutex; + } catch (std::system_error & ex) { + SDL_SetError("unable to create a C++ mutex: code=%d; %s", ex.code(), ex.what()); + return NULL; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + return NULL; + } +} + +/* Free the mutex */ +extern "C" +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + delete mutex; + } +} + +/* Lock the semaphore */ +extern "C" +int +SDL_mutexP(SDL_mutex * mutex) +{ + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + try { + mutex->cpp_mutex.lock(); + return 0; + } catch (std::system_error & ex) { + SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what()); + return -1; + } +} + +/* TryLock the mutex */ +int +SDL_TryLockMutex(SDL_mutex * mutex) +{ + int retval = 0; + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + if (mutex->cpp_mutex.try_lock() == false) { + retval = SDL_MUTEX_TIMEDOUT; + } + return retval; +} + +/* Unlock the mutex */ +extern "C" +int +SDL_mutexV(SDL_mutex * mutex) +{ + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + mutex->cpp_mutex.unlock(); + return 0; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex_c.h b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex_c.h new file mode 100644 index 0000000..000288f --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_sysmutex_c.h @@ -0,0 +1,30 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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_config.h" + +#include <mutex> + +struct SDL_mutex +{ + std::recursive_mutex cpp_mutex; +}; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread.cpp b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread.cpp new file mode 100644 index 0000000..3020f1c --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread.cpp @@ -0,0 +1,168 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +/* Thread management routines for SDL */ + +extern "C" { +#include "SDL_thread.h" +#include "../SDL_thread_c.h" +#include "../SDL_systhread.h" +#include "SDL_log.h" +} + +#include <mutex> +#include <thread> +#include <system_error> + +#ifdef __WINRT__ +#include <Windows.h> +#endif + +static void +RunThread(void *args) +{ + SDL_RunThread(args); +} + +extern "C" +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args) +{ + try { + // !!! FIXME: no way to set a thread stack size here. + std::thread cpp_thread(RunThread, args); + thread->handle = (void *) new std::thread(std::move(cpp_thread)); + return 0; + } catch (std::system_error & ex) { + SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what()); + return -1; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + return -1; + } +} + +extern "C" +void +SDL_SYS_SetupThread(const char *name) +{ + // Make sure a thread ID gets assigned ASAP, for debugging purposes: + SDL_ThreadID(); + return; +} + +extern "C" +SDL_threadID +SDL_ThreadID(void) +{ +#ifdef __WINRT__ + return GetCurrentThreadId(); +#else + // HACK: Mimick a thread ID, if one isn't otherwise available. + static thread_local SDL_threadID current_thread_id = 0; + static SDL_threadID next_thread_id = 1; + static std::mutex next_thread_id_mutex; + + if (current_thread_id == 0) { + std::lock_guard<std::mutex> lock(next_thread_id_mutex); + current_thread_id = next_thread_id; + ++next_thread_id; + } + + return current_thread_id; +#endif +} + +extern "C" +int +SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + // Thread priorities do not look to be settable via C++11's thread + // interface, at least as of this writing (Nov 2012). std::thread does + // provide access to the OS' native handle, however, and some form of + // priority-setting could, in theory, be done through this interface. + // + // WinRT: UPDATE (Aug 20, 2013): thread priorities cannot be changed + // on WinRT, at least not for any thread that's already been created. + // WinRT threads appear to be based off of the WinRT class, + // ThreadPool, more info on which can be found at: + // http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.threading.threadpool.aspx + // + // For compatibility sake, 0 will be returned here. + return (0); +} + +extern "C" +void +SDL_SYS_WaitThread(SDL_Thread * thread) +{ + if ( ! thread) { + return; + } + + try { + std::thread * cpp_thread = (std::thread *) thread->handle; + if (cpp_thread->joinable()) { + cpp_thread->join(); + } + } catch (std::system_error &) { + // An error occurred when joining the thread. SDL_WaitThread does not, + // however, seem to provide a means to report errors to its callers + // though! + } +} + +extern "C" +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + if ( ! thread) { + return; + } + + try { + std::thread * cpp_thread = (std::thread *) thread->handle; + if (cpp_thread->joinable()) { + cpp_thread->detach(); + } + } catch (std::system_error &) { + // An error occurred when detaching the thread. SDL_DetachThread does not, + // however, seem to provide a means to report errors to its callers + // though! + } +} + +extern "C" +SDL_TLSData * +SDL_SYS_GetTLSData(void) +{ + return SDL_Generic_GetTLSData(); +} + +extern "C" +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + return SDL_Generic_SetTLSData(data); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread_c.h b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread_c.h new file mode 100644 index 0000000..ee4764d --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/stdcpp/SDL_systhread_c.h @@ -0,0 +1,26 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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_config.h" + +/* For a thread handle, use a void pointer to a std::thread */ +typedef void * SYS_ThreadHandle; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/windows/SDL_sysmutex.c b/source/3rd-party/SDL2/src/thread/windows/SDL_sysmutex.c new file mode 100644 index 0000000..119e62b --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/windows/SDL_sysmutex.c @@ -0,0 +1,110 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_WINDOWS + +/* Mutex functions using the Win32 API */ + +#include "../../core/windows/SDL_windows.h" + +#include "SDL_mutex.h" + + +struct SDL_mutex +{ + CRITICAL_SECTION cs; +}; + +/* Create a mutex */ +SDL_mutex * +SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + + /* Allocate mutex memory */ + mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex)); + if (mutex) { + /* Initialize */ + /* On SMP systems, a non-zero spin count generally helps performance */ +#if __WINRT__ + InitializeCriticalSectionEx(&mutex->cs, 2000, 0); +#else + InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000); +#endif + } else { + SDL_OutOfMemory(); + } + return (mutex); +} + +/* Free the mutex */ +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + DeleteCriticalSection(&mutex->cs); + SDL_free(mutex); + } +} + +/* Lock the mutex */ +int +SDL_LockMutex(SDL_mutex * mutex) +{ + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + EnterCriticalSection(&mutex->cs); + return (0); +} + +/* TryLock the mutex */ +int +SDL_TryLockMutex(SDL_mutex * mutex) +{ + int retval = 0; + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + if (TryEnterCriticalSection(&mutex->cs) == 0) { + retval = SDL_MUTEX_TIMEDOUT; + } + return retval; +} + +/* Unlock the mutex */ +int +SDL_UnlockMutex(SDL_mutex * mutex) +{ + if (mutex == NULL) { + return SDL_SetError("Passed a NULL mutex"); + } + + LeaveCriticalSection(&mutex->cs); + return (0); +} + +#endif /* SDL_THREAD_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/windows/SDL_syssem.c b/source/3rd-party/SDL2/src/thread/windows/SDL_syssem.c new file mode 100644 index 0000000..dcb36fa --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/windows/SDL_syssem.c @@ -0,0 +1,152 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_WINDOWS + +/* Semaphore functions using the Win32 API */ + +#include "../../core/windows/SDL_windows.h" + +#include "SDL_thread.h" + +struct SDL_semaphore +{ + HANDLE id; + LONG count; +}; + + +/* Create a semaphore */ +SDL_sem * +SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem; + + /* Allocate sem memory */ + sem = (SDL_sem *) SDL_malloc(sizeof(*sem)); + if (sem) { + /* Create the semaphore, with max value 32K */ +#if __WINRT__ + sem->id = CreateSemaphoreEx(NULL, initial_value, 32 * 1024, NULL, 0, SEMAPHORE_ALL_ACCESS); +#else + sem->id = CreateSemaphore(NULL, initial_value, 32 * 1024, NULL); +#endif + sem->count = initial_value; + if (!sem->id) { + SDL_SetError("Couldn't create semaphore"); + SDL_free(sem); + sem = NULL; + } + } else { + SDL_OutOfMemory(); + } + return (sem); +} + +/* Free the semaphore */ +void +SDL_DestroySemaphore(SDL_sem * sem) +{ + if (sem) { + if (sem->id) { + CloseHandle(sem->id); + sem->id = 0; + } + SDL_free(sem); + } +} + +int +SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) +{ + int retval; + DWORD dwMilliseconds; + + if (!sem) { + return SDL_SetError("Passed a NULL sem"); + } + + if (timeout == SDL_MUTEX_MAXWAIT) { + dwMilliseconds = INFINITE; + } else { + dwMilliseconds = (DWORD) timeout; + } + switch (WaitForSingleObjectEx(sem->id, dwMilliseconds, FALSE)) { + case WAIT_OBJECT_0: + InterlockedDecrement(&sem->count); + retval = 0; + break; + case WAIT_TIMEOUT: + retval = SDL_MUTEX_TIMEDOUT; + break; + default: + retval = SDL_SetError("WaitForSingleObject() failed"); + break; + } + return retval; +} + +int +SDL_SemTryWait(SDL_sem * sem) +{ + return SDL_SemWaitTimeout(sem, 0); +} + +int +SDL_SemWait(SDL_sem * sem) +{ + return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +Uint32 +SDL_SemValue(SDL_sem * sem) +{ + if (!sem) { + SDL_SetError("Passed a NULL sem"); + return 0; + } + return (Uint32)sem->count; +} + +int +SDL_SemPost(SDL_sem * sem) +{ + if (!sem) { + return SDL_SetError("Passed a NULL sem"); + } + /* Increase the counter in the first place, because + * after a successful release the semaphore may + * immediately get destroyed by another thread which + * is waiting for this semaphore. + */ + InterlockedIncrement(&sem->count); + if (ReleaseSemaphore(sem->id, 1, NULL) == FALSE) { + InterlockedDecrement(&sem->count); /* restore */ + return SDL_SetError("ReleaseSemaphore() failed"); + } + return 0; +} + +#endif /* SDL_THREAD_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/windows/SDL_systhread.c b/source/3rd-party/SDL2/src/thread/windows/SDL_systhread.c new file mode 100644 index 0000000..251510d --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/windows/SDL_systhread.c @@ -0,0 +1,260 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_WINDOWS + +/* Win32 thread management routines for SDL */ + +#include "SDL_hints.h" +#include "SDL_thread.h" +#include "../SDL_thread_c.h" +#include "../SDL_systhread.h" +#include "SDL_systhread_c.h" + +#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD +/* We'll use the C library from this DLL */ +#include <process.h> + +#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 +#endif + +/* Cygwin gcc-3 ... MingW64 (even with a i386 host) does this like MSVC. */ +#if (defined(__MINGW32__) && (__GNUC__ < 4)) +typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, + unsigned (__stdcall *func)(void *), void *arg, + unsigned, unsigned *threadID); +typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); + +#elif defined(__WATCOMC__) +/* This is for Watcom targets except OS2 */ +#if __WATCOMC__ < 1240 +#define __watcall +#endif +typedef unsigned long (__watcall * pfnSDL_CurrentBeginThread) (void *, + unsigned, + unsigned + (__stdcall * + func) (void + *), + void *arg, + unsigned, + unsigned + *threadID); +typedef void (__watcall * pfnSDL_CurrentEndThread) (unsigned code); + +#else +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 +#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */ + + +typedef struct ThreadStartParms +{ + void *args; + pfnSDL_CurrentEndThread pfnCurrentEndThread; +} tThreadStartParms, *pThreadStartParms; + +static DWORD +RunThread(void *data) +{ + pThreadStartParms pThreadParms = (pThreadStartParms) data; + pfnSDL_CurrentEndThread pfnEndThread = pThreadParms->pfnCurrentEndThread; + void *args = pThreadParms->args; + SDL_free(pThreadParms); + SDL_RunThread(args); + if (pfnEndThread != NULL) + pfnEndThread(0); + return (0); +} + +static DWORD WINAPI +RunThreadViaCreateThread(LPVOID data) +{ + return RunThread(data); +} + +static unsigned __stdcall +RunThreadViaBeginThreadEx(void *data) +{ + return (unsigned) RunThread(data); +} + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread) +{ +#elif defined(__CYGWIN__) || defined(__WINRT__) +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args) +{ + pfnSDL_CurrentBeginThread pfnBeginThread = NULL; + pfnSDL_CurrentEndThread pfnEndThread = NULL; +#else +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args) +{ + pfnSDL_CurrentBeginThread pfnBeginThread = (pfnSDL_CurrentBeginThread)_beginthreadex; + pfnSDL_CurrentEndThread pfnEndThread = (pfnSDL_CurrentEndThread)_endthreadex; +#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ + pThreadStartParms pThreadParms = + (pThreadStartParms) SDL_malloc(sizeof(tThreadStartParms)); + const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0; + if (!pThreadParms) { + return SDL_OutOfMemory(); + } + /* Save the function which we will have to call to clear the RTL of calling app! */ + pThreadParms->pfnCurrentEndThread = pfnEndThread; + /* Also save the real parameters we have to pass to thread function */ + pThreadParms->args = args; + + /* thread->stacksize == 0 means "system default", same as win32 expects */ + if (pfnBeginThread) { + unsigned threadid = 0; + thread->handle = (SYS_ThreadHandle) + ((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize, + RunThreadViaBeginThreadEx, + pThreadParms, flags, &threadid)); + } else { + DWORD threadid = 0; + thread->handle = CreateThread(NULL, thread->stacksize, + RunThreadViaCreateThread, + pThreadParms, flags, &threadid); + } + if (thread->handle == NULL) { + return SDL_SetError("Not enough resources to create thread"); + } + return 0; +} + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; /* must be 0x1000 */ + LPCSTR szName; /* pointer to name (in user addr space) */ + DWORD dwThreadID; /* thread ID (-1=caller thread) */ + DWORD dwFlags; /* reserved for future use, must be zero */ +} THREADNAME_INFO; +#pragma pack(pop) + + +typedef HRESULT (WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR); + +void +SDL_SYS_SetupThread(const char *name) +{ + if (name != NULL) { + #ifndef __WINRT__ /* !!! FIXME: There's no LoadLibrary() in WinRT; don't know if SetThreadDescription is available there at all at the moment. */ + static pfnSetThreadDescription pSetThreadDescription = NULL; + static HMODULE kernel32 = 0; + + if (!kernel32) { + kernel32 = LoadLibraryW(L"kernel32.dll"); + if (kernel32) { + pSetThreadDescription = (pfnSetThreadDescription) GetProcAddress(kernel32, "SetThreadDescription"); + } + } + + if (pSetThreadDescription != NULL) { + WCHAR *strw = WIN_UTF8ToString(name); + if (strw) { + pSetThreadDescription(GetCurrentThread(), strw); + SDL_free(strw); + } + } + #endif + + /* Presumably some version of Visual Studio will understand SetThreadDescription(), + but we still need to deal with older OSes and debuggers. Set it with the arcane + exception magic, too. */ + + if (IsDebuggerPresent()) { + THREADNAME_INFO inf; + + /* C# and friends will try to catch this Exception, let's avoid it. */ + if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, SDL_TRUE)) { + return; + } + + /* This magic tells the debugger to name a thread if it's listening. */ + SDL_zero(inf); + inf.dwType = 0x1000; + inf.szName = name; + inf.dwThreadID = (DWORD) -1; + inf.dwFlags = 0; + + /* The debugger catches this, renames the thread, continues on. */ + RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf); + } + } +} + +SDL_threadID +SDL_ThreadID(void) +{ + return ((SDL_threadID) GetCurrentThreadId()); +} + +int +SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + int value; + + if (priority == SDL_THREAD_PRIORITY_LOW) { + value = THREAD_PRIORITY_LOWEST; + } else if (priority == SDL_THREAD_PRIORITY_HIGH) { + value = THREAD_PRIORITY_HIGHEST; + } else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) { + value = THREAD_PRIORITY_TIME_CRITICAL; + } else { + value = THREAD_PRIORITY_NORMAL; + } + if (!SetThreadPriority(GetCurrentThread(), value)) { + return WIN_SetError("SetThreadPriority()"); + } + return 0; +} + +void +SDL_SYS_WaitThread(SDL_Thread * thread) +{ + WaitForSingleObjectEx(thread->handle, INFINITE, FALSE); + CloseHandle(thread->handle); +} + +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + CloseHandle(thread->handle); +} + +#endif /* SDL_THREAD_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/windows/SDL_systhread_c.h b/source/3rd-party/SDL2/src/thread/windows/SDL_systhread_c.h new file mode 100644 index 0000000..65d5a1b --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/windows/SDL_systhread_c.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#ifndef SDL_systhread_c_h_ +#define SDL_systhread_c_h_ + +#include "../../core/windows/SDL_windows.h" + +typedef HANDLE SYS_ThreadHandle; + +#endif /* SDL_systhread_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/thread/windows/SDL_systls.c b/source/3rd-party/SDL2/src/thread/windows/SDL_systls.c new file mode 100644 index 0000000..888fd74 --- /dev/null +++ b/source/3rd-party/SDL2/src/thread/windows/SDL_systls.c @@ -0,0 +1,72 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_THREAD_WINDOWS + +#include "../../core/windows/SDL_windows.h" + +#include "SDL_thread.h" +#include "../SDL_thread_c.h" + +static DWORD thread_local_storage = TLS_OUT_OF_INDEXES; +static SDL_bool generic_local_storage = SDL_FALSE; + +SDL_TLSData * +SDL_SYS_GetTLSData(void) +{ + if (thread_local_storage == TLS_OUT_OF_INDEXES && !generic_local_storage) { + static SDL_SpinLock lock; + SDL_AtomicLock(&lock); + if (thread_local_storage == TLS_OUT_OF_INDEXES && !generic_local_storage) { + DWORD storage = TlsAlloc(); + if (storage != TLS_OUT_OF_INDEXES) { + SDL_MemoryBarrierRelease(); + thread_local_storage = storage; + } else { + generic_local_storage = SDL_TRUE; + } + } + SDL_AtomicUnlock(&lock); + } + if (generic_local_storage) { + return SDL_Generic_GetTLSData(); + } + SDL_MemoryBarrierAcquire(); + return (SDL_TLSData *)TlsGetValue(thread_local_storage); +} + +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + if (generic_local_storage) { + return SDL_Generic_SetTLSData(data); + } + if (!TlsSetValue(thread_local_storage, data)) { + return SDL_SetError("TlsSetValue() failed"); + } + return 0; +} + +#endif /* SDL_THREAD_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */ |