Implemented an API for thread-local storage: SDL_TLSCreate(), SDL_TLSSet(), SDL_TLSGet()
This commit is contained in:
parent
ab91b4ce14
commit
bfcb08d569
14 changed files with 618 additions and 156 deletions
|
@ -22,158 +22,46 @@
|
|||
|
||||
/* System independent thread management routines for SDL */
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
#include "SDL_thread.h"
|
||||
#include "SDL_thread_c.h"
|
||||
#include "SDL_systhread.h"
|
||||
#include "../SDL_error_c.h"
|
||||
|
||||
#define ARRAY_CHUNKSIZE 32
|
||||
/* The array of threads currently active in the application
|
||||
(except the main thread)
|
||||
The manipulation of an array here is safer than using a linked list.
|
||||
*/
|
||||
static int SDL_maxthreads = 0;
|
||||
static int SDL_numthreads = 0;
|
||||
static SDL_Thread **SDL_Threads = NULL;
|
||||
static SDL_mutex *thread_lock = NULL;
|
||||
|
||||
static int
|
||||
SDL_ThreadsInit(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = 0;
|
||||
thread_lock = SDL_CreateMutex();
|
||||
if (thread_lock == NULL) {
|
||||
retval = -1;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* This should never be called...
|
||||
If this is called by SDL_Quit(), we don't know whether or not we should
|
||||
clean up threads here. If any threads are still running after this call,
|
||||
they will no longer have access to any per-thread data.
|
||||
*/
|
||||
#if 0
|
||||
static void
|
||||
SDL_ThreadsQuit(void)
|
||||
{
|
||||
SDL_mutex *mutex;
|
||||
|
||||
mutex = thread_lock;
|
||||
thread_lock = NULL;
|
||||
if (mutex != NULL) {
|
||||
SDL_DestroyMutex(mutex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Routines for manipulating the thread list */
|
||||
static void
|
||||
SDL_AddThread(SDL_Thread * thread)
|
||||
{
|
||||
/* WARNING:
|
||||
If the very first threads are created simultaneously, then
|
||||
there could be a race condition causing memory corruption.
|
||||
In practice, this isn't a problem because by definition there
|
||||
is only one thread running the first time this is called.
|
||||
*/
|
||||
if (!thread_lock) {
|
||||
if (SDL_ThreadsInit() < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SDL_LockMutex(thread_lock);
|
||||
|
||||
/* Expand the list of threads, if necessary */
|
||||
#ifdef DEBUG_THREADS
|
||||
printf("Adding thread (%d already - %d max)\n",
|
||||
SDL_numthreads, SDL_maxthreads);
|
||||
#endif
|
||||
if (SDL_numthreads == SDL_maxthreads) {
|
||||
SDL_Thread **threads;
|
||||
threads = (SDL_Thread **) SDL_realloc(SDL_Threads,
|
||||
(SDL_maxthreads +
|
||||
ARRAY_CHUNKSIZE) *
|
||||
(sizeof *threads));
|
||||
if (threads == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
goto done;
|
||||
}
|
||||
SDL_maxthreads += ARRAY_CHUNKSIZE;
|
||||
SDL_Threads = threads;
|
||||
}
|
||||
SDL_Threads[SDL_numthreads++] = thread;
|
||||
done:
|
||||
SDL_mutexV(thread_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_DelThread(SDL_Thread * thread)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!thread_lock) {
|
||||
return;
|
||||
}
|
||||
SDL_LockMutex(thread_lock);
|
||||
for (i = 0; i < SDL_numthreads; ++i) {
|
||||
if (thread == SDL_Threads[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < SDL_numthreads) {
|
||||
if (--SDL_numthreads > 0) {
|
||||
while (i < SDL_numthreads) {
|
||||
SDL_Threads[i] = SDL_Threads[i + 1];
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
SDL_maxthreads = 0;
|
||||
SDL_free(SDL_Threads);
|
||||
SDL_Threads = NULL;
|
||||
}
|
||||
#ifdef DEBUG_THREADS
|
||||
printf("Deleting thread (%d left - %d max)\n",
|
||||
SDL_numthreads, SDL_maxthreads);
|
||||
#endif
|
||||
}
|
||||
SDL_mutexV(thread_lock);
|
||||
|
||||
#if 0 /* There could be memory corruption if another thread is starting */
|
||||
if (SDL_Threads == NULL) {
|
||||
SDL_ThreadsQuit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The default (non-thread-safe) global error variable */
|
||||
static SDL_error SDL_global_error;
|
||||
|
||||
/* Routine to get the thread-specific error variable */
|
||||
SDL_error *
|
||||
SDL_GetErrBuf(void)
|
||||
{
|
||||
static SDL_SpinLock spinlock;
|
||||
static SDL_bool tls_being_created;
|
||||
static SDL_TLSID tls_errbuf;
|
||||
static SDL_error SDL_global_errbuf;
|
||||
SDL_error *errbuf;
|
||||
|
||||
errbuf = &SDL_global_error;
|
||||
if (SDL_Threads) {
|
||||
int i;
|
||||
SDL_threadID this_thread;
|
||||
|
||||
this_thread = SDL_ThreadID();
|
||||
SDL_LockMutex(thread_lock);
|
||||
for (i = 0; i < SDL_numthreads; ++i) {
|
||||
if (this_thread == SDL_Threads[i]->threadid) {
|
||||
errbuf = &SDL_Threads[i]->errbuf;
|
||||
break;
|
||||
}
|
||||
if (!tls_errbuf && !tls_being_created) {
|
||||
SDL_AtomicLock(&spinlock);
|
||||
if (!tls_errbuf) {
|
||||
/* SDL_TLSCreate() could fail and call SDL_SetError() */
|
||||
tls_being_created = SDL_TRUE;
|
||||
tls_errbuf = SDL_TLSCreate();
|
||||
tls_being_created = SDL_FALSE;
|
||||
}
|
||||
SDL_mutexV(thread_lock);
|
||||
SDL_AtomicUnlock(&spinlock);
|
||||
}
|
||||
return (errbuf);
|
||||
if (!tls_errbuf) {
|
||||
return &SDL_global_errbuf;
|
||||
}
|
||||
|
||||
errbuf = SDL_TLSGet(tls_errbuf);
|
||||
if (!errbuf) {
|
||||
errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
|
||||
if (!errbuf) {
|
||||
return &SDL_global_errbuf;
|
||||
}
|
||||
SDL_zerop(errbuf);
|
||||
SDL_TLSSet(tls_errbuf, errbuf);
|
||||
}
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
|
||||
|
@ -264,9 +152,6 @@ SDL_CreateThread(int (SDLCALL * fn) (void *),
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
/* Add the thread to the list of available threads */
|
||||
SDL_AddThread(thread);
|
||||
|
||||
/* Create the thread and go! */
|
||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
|
||||
|
@ -278,7 +163,6 @@ SDL_CreateThread(int (SDLCALL * fn) (void *),
|
|||
SDL_SemWait(args->wait);
|
||||
} else {
|
||||
/* Oops, failed. Gotta free everything */
|
||||
SDL_DelThread(thread);
|
||||
SDL_free(thread->name);
|
||||
SDL_free(thread);
|
||||
thread = NULL;
|
||||
|
@ -323,7 +207,6 @@ SDL_WaitThread(SDL_Thread * thread, int *status)
|
|||
if (status) {
|
||||
*status = thread->status;
|
||||
}
|
||||
SDL_DelThread(thread);
|
||||
SDL_free(thread->name);
|
||||
SDL_free(thread);
|
||||
}
|
||||
|
|
106
src/thread/beos/SDL_systls.c
Normal file
106
src/thread/beos/SDL_systls.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2013 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 "SDL_thread.h"
|
||||
|
||||
#if SDL_THREAD_BEOS
|
||||
|
||||
#include <support/TLS.h>
|
||||
|
||||
|
||||
#define TLS_ALLOC_CHUNKSIZE 8
|
||||
|
||||
typedef struct {
|
||||
int limit;
|
||||
void *data[1];
|
||||
} SDL_TLSData;
|
||||
|
||||
static SDL_SpinLock tls_lock;
|
||||
static int32 thread_local_storage = B_NO_MEMORY;
|
||||
static SDL_atomic_t tls_id;
|
||||
|
||||
|
||||
SDL_TLSID
|
||||
SDL_TLSCreate()
|
||||
{
|
||||
if (thread_local_storage == B_NO_MEMORY) {
|
||||
SDL_AtomicLock(&tls_lock);
|
||||
if (thread_local_storage == B_NO_MEMORY) {
|
||||
thread_local_storage = tls_allocate();
|
||||
if (thread_local_storage == B_NO_MEMORY) {
|
||||
SDL_SetError("tls_allocate() failed");
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
}
|
||||
return SDL_AtomicIncRef(&tls_id)+1;
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_TLSGet(SDL_TLSID id)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
data = (SDL_TLSData *)tls_get(thread_local_storage);
|
||||
if (!data || id <= 0 || id > data->limit) {
|
||||
return NULL;
|
||||
}
|
||||
return data->data[id-1];
|
||||
}
|
||||
|
||||
int
|
||||
SDL_TLSSet(SDL_TLSID id, const void *value)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
if (thread_local_storage == B_NO_MEMORY || id <= 0) {
|
||||
return SDL_InvalidParamError(id);
|
||||
}
|
||||
|
||||
data = (SDL_TLSData *)tls_get(thread_local_storage);
|
||||
if (!data || id > data->limit) {
|
||||
int i, oldlimit, newlimit;
|
||||
|
||||
oldlimit = data ? data->limit : 0;
|
||||
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
||||
data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
data->limit = newlimit;
|
||||
for (i = oldlimit; i < newlimit; ++i) {
|
||||
data->data[i] = NULL;
|
||||
}
|
||||
if (!tls_set(thread_local_storage, data)) {
|
||||
return SDL_SetError("TlsSetValue() failed");
|
||||
}
|
||||
}
|
||||
|
||||
data->data[id-1] = SDL_const_cast(void*, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_BEOS */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
163
src/thread/generic/SDL_systls.c
Normal file
163
src/thread/generic/SDL_systls.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2013 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 "SDL_thread.h"
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#define TLS_ALLOC_CHUNKSIZE 8
|
||||
|
||||
typedef struct {
|
||||
int limit;
|
||||
void *data[1];
|
||||
} SDL_TLSData;
|
||||
|
||||
typedef struct SDL_TLSEntry {
|
||||
SDL_threadID thread;
|
||||
SDL_TLSData *data;
|
||||
struct SDL_TLSEntry *next;
|
||||
} SDL_TLSEntry;
|
||||
|
||||
static SDL_SpinLock tls_lock;
|
||||
static SDL_mutex *tls_mutex;
|
||||
static SDL_TLSEntry *thread_local_storage;
|
||||
static SDL_atomic_t tls_id;
|
||||
|
||||
|
||||
static SDL_TLSData *GetTLSData()
|
||||
{
|
||||
SDL_threadID thread = SDL_ThreadID();
|
||||
SDL_TLSEntry *entry;
|
||||
SDL_TLSData *data = NULL;
|
||||
|
||||
if (!tls_mutex) {
|
||||
SDL_AtomicLock(&tls_lock);
|
||||
if (!tls_mutex) {
|
||||
tls_mutex = SDL_CreateMutex();
|
||||
if (!tls_mutex) {
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
}
|
||||
|
||||
SDL_LockMutex(tls_mutex);
|
||||
for (entry = thread_local_storage; entry; entry = entry->next) {
|
||||
if (entry->thread == thread) {
|
||||
data = entry->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(tls_mutex);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int SetTLSData(SDL_TLSData *data)
|
||||
{
|
||||
SDL_threadID thread = SDL_ThreadID();
|
||||
SDL_TLSEntry *entry;
|
||||
|
||||
/* GetTLSData() is always called first, so we can assume tls_mutex */
|
||||
SDL_LockMutex(tls_mutex);
|
||||
for (entry = thread_local_storage; entry; entry = entry->next) {
|
||||
if (entry->thread == thread) {
|
||||
entry->data = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!entry) {
|
||||
entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
|
||||
if (entry) {
|
||||
entry->thread = thread;
|
||||
entry->data = data;
|
||||
entry->next = thread_local_storage;
|
||||
thread_local_storage = entry;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(tls_mutex);
|
||||
|
||||
if (!entry) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SDL_TLSID
|
||||
SDL_TLSCreate()
|
||||
{
|
||||
return SDL_AtomicIncRef(&tls_id)+1;
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_TLSGet(SDL_TLSID id)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
data = GetTLSData();
|
||||
if (!data || id <= 0 || id > data->limit) {
|
||||
return NULL;
|
||||
}
|
||||
return data->data[id-1];
|
||||
}
|
||||
|
||||
int
|
||||
SDL_TLSSet(SDL_TLSID id, const void *value)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
if (id <= 0) {
|
||||
return SDL_InvalidParamError(id);
|
||||
}
|
||||
|
||||
data = GetTLSData();
|
||||
if (!data || id > data->limit) {
|
||||
int i, oldlimit, newlimit;
|
||||
|
||||
oldlimit = data ? data->limit : 0;
|
||||
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
||||
data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
data->limit = newlimit;
|
||||
for (i = oldlimit; i < newlimit; ++i) {
|
||||
data->data[i] = NULL;
|
||||
}
|
||||
if (SetTLSData(data) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
data->data[id-1] = SDL_const_cast(void*, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
101
src/thread/pthread/SDL_systls.c
Normal file
101
src/thread/pthread/SDL_systls.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2013 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 "SDL_thread.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
#define TLS_ALLOC_CHUNKSIZE 8
|
||||
|
||||
typedef struct {
|
||||
int limit;
|
||||
void *data[1];
|
||||
} SDL_TLSData;
|
||||
|
||||
static SDL_SpinLock tls_lock;
|
||||
static pthread_key_t thread_local_storage;
|
||||
static SDL_atomic_t tls_id;
|
||||
|
||||
|
||||
SDL_TLSID
|
||||
SDL_TLSCreate()
|
||||
{
|
||||
if (!thread_local_storage) {
|
||||
SDL_AtomicLock(&tls_lock);
|
||||
if (!thread_local_storage) {
|
||||
if (pthread_key_create(&thread_local_storage, NULL) != 0) {
|
||||
SDL_SetError("pthread_key_create() failed");
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
}
|
||||
return SDL_AtomicIncRef(&tls_id)+1;
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_TLSGet(SDL_TLSID id)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
data = (SDL_TLSData *)pthread_getspecific(thread_local_storage);
|
||||
if (!data || id <= 0 || id > data->limit) {
|
||||
return NULL;
|
||||
}
|
||||
return data->data[id-1];
|
||||
}
|
||||
|
||||
int
|
||||
SDL_TLSSet(SDL_TLSID id, const void *value)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
if (!thread_local_storage || id <= 0) {
|
||||
return SDL_InvalidParamError(id);
|
||||
}
|
||||
|
||||
data = (SDL_TLSData *)pthread_getspecific(thread_local_storage);
|
||||
if (!data || id > data->limit) {
|
||||
int i, oldlimit, newlimit;
|
||||
|
||||
oldlimit = data ? data->limit : 0;
|
||||
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
||||
data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
data->limit = newlimit;
|
||||
for (i = oldlimit; i < newlimit; ++i) {
|
||||
data->data[i] = NULL;
|
||||
}
|
||||
if (pthread_setspecific(thread_local_storage, data) != 0) {
|
||||
return SDL_SetError("pthread_setspecific() failed");
|
||||
}
|
||||
}
|
||||
|
||||
data->data[id-1] = SDL_const_cast(void*, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
106
src/thread/windows/SDL_systls.c
Normal file
106
src/thread/windows/SDL_systls.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2013 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 "SDL_thread.h"
|
||||
|
||||
#if SDL_THREAD_WINDOWS
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
|
||||
#define TLS_ALLOC_CHUNKSIZE 8
|
||||
|
||||
typedef struct {
|
||||
int limit;
|
||||
void *data[1];
|
||||
} SDL_TLSData;
|
||||
|
||||
static SDL_SpinLock tls_lock;
|
||||
static DWORD thread_local_storage = TLS_OUT_OF_INDEXES;
|
||||
static SDL_atomic_t tls_id;
|
||||
|
||||
|
||||
SDL_TLSID
|
||||
SDL_TLSCreate()
|
||||
{
|
||||
if (thread_local_storage == TLS_OUT_OF_INDEXES) {
|
||||
SDL_AtomicLock(&tls_lock);
|
||||
if (thread_local_storage == TLS_OUT_OF_INDEXES) {
|
||||
thread_local_storage = TlsAlloc();
|
||||
if (thread_local_storage == TLS_OUT_OF_INDEXES) {
|
||||
SDL_SetError("TlsAlloc() failed");
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SDL_AtomicUnlock(&tls_lock);
|
||||
}
|
||||
return SDL_AtomicIncRef(&tls_id)+1;
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_TLSGet(SDL_TLSID id)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
data = (SDL_TLSData *)TlsGetValue(thread_local_storage);
|
||||
if (!data || id <= 0 || id > data->limit) {
|
||||
return NULL;
|
||||
}
|
||||
return data->data[id-1];
|
||||
}
|
||||
|
||||
int
|
||||
SDL_TLSSet(SDL_TLSID id, const void *value)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
if (thread_local_storage == TLS_OUT_OF_INDEXES || id <= 0) {
|
||||
return SDL_InvalidParamError(id);
|
||||
}
|
||||
|
||||
data = (SDL_TLSData *)TlsGetValue(thread_local_storage);
|
||||
if (!data || id > data->limit) {
|
||||
int i, oldlimit, newlimit;
|
||||
|
||||
oldlimit = data ? data->limit : 0;
|
||||
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
||||
data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
data->limit = newlimit;
|
||||
for (i = oldlimit; i < newlimit; ++i) {
|
||||
data->data[i] = NULL;
|
||||
}
|
||||
if (!TlsSetValue(thread_local_storage, data)) {
|
||||
return SDL_SetError("TlsSetValue() failed");
|
||||
}
|
||||
}
|
||||
|
||||
data->data[id-1] = SDL_const_cast(void*, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_WINDOWS */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Add table
Add a link
Reference in a new issue