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: */  | 
