Added release/acquire memory barriers to the atomic API
* Added a destructor to clean up TLS memory at thread shutdown * Refactored the TLS code to have platform independent code and a small platform dependent core with a fallback to generic code if platform dependent functions fail. * Fixed recursion issues with SDL_GetErrBuf()
This commit is contained in:
parent
086ecc9949
commit
557bbf3fe6
10 changed files with 334 additions and 319 deletions
|
@ -18,83 +18,51 @@
|
|||
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 "../SDL_thread_c.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
#define TLS_ALLOC_CHUNKSIZE 8
|
||||
#define INVALID_PTHREAD_KEY ((pthread_key_t)-1)
|
||||
|
||||
typedef struct {
|
||||
int limit;
|
||||
void *data[1];
|
||||
} SDL_TLSData;
|
||||
static pthread_key_t thread_local_storage = INVALID_PTHREAD_KEY;
|
||||
static SDL_bool generic_local_storage = SDL_FALSE;
|
||||
|
||||
static SDL_SpinLock tls_lock;
|
||||
static pthread_key_t thread_local_storage;
|
||||
static SDL_atomic_t tls_id;
|
||||
|
||||
|
||||
SDL_TLSID
|
||||
SDL_TLSCreate()
|
||||
SDL_TLSData *
|
||||
SDL_SYS_GetTLSData()
|
||||
{
|
||||
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;
|
||||
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(&tls_lock);
|
||||
SDL_AtomicUnlock(&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;
|
||||
if (generic_local_storage) {
|
||||
return SDL_Generic_GetTLSData();
|
||||
}
|
||||
return data->data[id-1];
|
||||
SDL_MemoryBarrierAcquire();
|
||||
return (SDL_TLSData *)pthread_getspecific(thread_local_storage);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_TLSSet(SDL_TLSID id, const void *value)
|
||||
SDL_SYS_SetTLSData(SDL_TLSData *data)
|
||||
{
|
||||
SDL_TLSData *data;
|
||||
|
||||
if (!thread_local_storage || id <= 0) {
|
||||
return SDL_InvalidParamError(id);
|
||||
if (generic_local_storage) {
|
||||
return SDL_Generic_SetTLSData(data);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue