mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-04-18 14:38:44 +02:00
Removed the need for SDL_CreateTLS()
This eliminates the tap dancing needed for allocating TLS slots, we'll automatically allocate them as needed, in a thread-safe way.
This commit is contained in:
@@ -71,7 +71,6 @@ SDL3_0.0.0 {
|
||||
SDL_CreateSurfaceFrom;
|
||||
SDL_CreateSurfacePalette;
|
||||
SDL_CreateSystemCursor;
|
||||
SDL_CreateTLS;
|
||||
SDL_CreateTexture;
|
||||
SDL_CreateTextureFromSurface;
|
||||
SDL_CreateTextureWithProperties;
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
#define SDL_CreateSurfaceFrom SDL_CreateSurfaceFrom_REAL
|
||||
#define SDL_CreateSurfacePalette SDL_CreateSurfacePalette_REAL
|
||||
#define SDL_CreateSystemCursor SDL_CreateSystemCursor_REAL
|
||||
#define SDL_CreateTLS SDL_CreateTLS_REAL
|
||||
#define SDL_CreateTexture SDL_CreateTexture_REAL
|
||||
#define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL
|
||||
#define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL
|
||||
|
||||
@@ -116,7 +116,6 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateSurface,(int a, int b, SDL_PixelFormat c)
|
||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateSurfaceFrom,(int a, int b, SDL_PixelFormat c, void *d, int e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(SDL_Palette*,SDL_CreateSurfacePalette,(SDL_Surface *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateSystemCursor,(SDL_SystemCursor a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_TLSID,SDL_CreateTLS,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTexture,(SDL_Renderer *a, SDL_PixelFormat b, int c, int d, int e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureFromSurface,(SDL_Renderer *a, SDL_Surface *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureWithProperties,(SDL_Renderer *a, SDL_PropertiesID b),(a,b),return)
|
||||
@@ -484,7 +483,7 @@ SDL_DYNAPI_PROC(SDL_Palette*,SDL_GetSurfacePalette,(SDL_Surface *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetSurfaceProperties,(SDL_Surface *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetSystemRAM,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_SystemTheme,SDL_GetSystemTheme,(void),(),return)
|
||||
SDL_DYNAPI_PROC(void*,SDL_GetTLS,(SDL_TLSID a),(a),return)
|
||||
SDL_DYNAPI_PROC(void*,SDL_GetTLS,(SDL_TLSID *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetTextInputArea,(SDL_Window *a, SDL_Rect *b, int *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetTextureAlphaMod,(SDL_Texture *a, Uint8 *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetTextureAlphaModFloat,(SDL_Texture *a, float *b),(a,b),return)
|
||||
@@ -792,7 +791,7 @@ SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorMod,(SDL_Surface *a, Uint8 b, Uint8 c, Ui
|
||||
SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetSurfacePalette,(SDL_Surface *a, SDL_Palette *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetSurfaceRLE,(SDL_Surface *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetTLS,(SDL_TLSID a, const void *b, SDL_TLSDestructorCallback c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetTLS,(SDL_TLSID *a, const void *b, SDL_TLSDestructorCallback c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetTextInputArea,(SDL_Window *a, const SDL_Rect *b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetTextureAlphaMod,(SDL_Texture *a, Uint8 b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetTextureAlphaModFloat,(SDL_Texture *a, float b),(a,b),return)
|
||||
|
||||
@@ -29,34 +29,37 @@
|
||||
/* The storage is local to the thread, but the IDs are global for the process */
|
||||
|
||||
static SDL_AtomicInt SDL_tls_allocated;
|
||||
static SDL_AtomicInt SDL_tls_id;
|
||||
|
||||
void SDL_InitTLSData(void)
|
||||
{
|
||||
SDL_SYS_InitTLSData();
|
||||
}
|
||||
|
||||
SDL_TLSID SDL_CreateTLS(void)
|
||||
{
|
||||
static SDL_AtomicInt SDL_tls_id;
|
||||
return (SDL_TLSID)(SDL_AtomicIncRef(&SDL_tls_id) + 1);
|
||||
}
|
||||
|
||||
void *SDL_GetTLS(SDL_TLSID id)
|
||||
void *SDL_GetTLS(SDL_TLSID *id)
|
||||
{
|
||||
SDL_TLSData *storage;
|
||||
int storage_index;
|
||||
|
||||
storage = SDL_SYS_GetTLSData();
|
||||
if (!storage || id == 0 || id > storage->limit) {
|
||||
if (id == NULL) {
|
||||
SDL_InvalidParamError("id");
|
||||
return NULL;
|
||||
}
|
||||
return storage->array[id - 1].data;
|
||||
|
||||
storage_index = SDL_AtomicGet(id) - 1;
|
||||
storage = SDL_SYS_GetTLSData();
|
||||
if (!storage || storage_index < 0 || storage_index >= storage->limit) {
|
||||
return NULL;
|
||||
}
|
||||
return storage->array[storage_index].data;
|
||||
}
|
||||
|
||||
int SDL_SetTLS(SDL_TLSID id, const void *value, SDL_TLSDestructorCallback destructor)
|
||||
int SDL_SetTLS(SDL_TLSID *id, const void *value, SDL_TLSDestructorCallback destructor)
|
||||
{
|
||||
SDL_TLSData *storage;
|
||||
int storage_index;
|
||||
|
||||
if (id == 0) {
|
||||
if (id == NULL) {
|
||||
return SDL_InvalidParamError("id");
|
||||
}
|
||||
|
||||
@@ -66,14 +69,27 @@ int SDL_SetTLS(SDL_TLSID id, const void *value, SDL_TLSDestructorCallback destru
|
||||
*/
|
||||
SDL_InitTLSData();
|
||||
|
||||
/* Get the storage index associated with the ID in a thread-safe way */
|
||||
storage_index = SDL_AtomicGet(id) - 1;
|
||||
if (storage_index < 0) {
|
||||
int new_id = (SDL_AtomicIncRef(&SDL_tls_id) + 1);
|
||||
|
||||
SDL_AtomicCompareAndSwap(id, 0, new_id);
|
||||
|
||||
/* If there was a race condition we'll have wasted an ID, but every thread
|
||||
* will have the same storage index for this id.
|
||||
*/
|
||||
storage_index = SDL_AtomicGet(id) - 1;
|
||||
}
|
||||
|
||||
/* Get the storage for the current thread */
|
||||
storage = SDL_SYS_GetTLSData();
|
||||
if (!storage || (id > storage->limit)) {
|
||||
if (!storage || storage_index >= storage->limit) {
|
||||
unsigned int i, oldlimit, newlimit;
|
||||
SDL_TLSData *new_storage;
|
||||
|
||||
oldlimit = storage ? storage->limit : 0;
|
||||
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
||||
newlimit = (storage_index + TLS_ALLOC_CHUNKSIZE);
|
||||
new_storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage) + (newlimit - 1) * sizeof(storage->array[0]));
|
||||
if (!new_storage) {
|
||||
return -1;
|
||||
@@ -91,8 +107,8 @@ int SDL_SetTLS(SDL_TLSID id, const void *value, SDL_TLSDestructorCallback destru
|
||||
SDL_AtomicIncRef(&SDL_tls_allocated);
|
||||
}
|
||||
|
||||
storage->array[id - 1].data = SDL_const_cast(void *, value);
|
||||
storage->array[id - 1].destructor = destructor;
|
||||
storage->array[storage_index].data = SDL_const_cast(void *, value);
|
||||
storage->array[storage_index].destructor = destructor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -103,7 +119,7 @@ void SDL_CleanupTLS(void)
|
||||
/* Cleanup the storage for the current thread */
|
||||
storage = SDL_SYS_GetTLSData();
|
||||
if (storage) {
|
||||
unsigned int i;
|
||||
int i;
|
||||
for (i = 0; i < storage->limit; ++i) {
|
||||
if (storage->array[i].destructor) {
|
||||
storage->array[i].destructor(storage->array[i].data);
|
||||
@@ -261,42 +277,15 @@ SDL_error *SDL_GetErrBuf(SDL_bool create)
|
||||
#ifdef SDL_THREADS_DISABLED
|
||||
return SDL_GetStaticErrBuf();
|
||||
#else
|
||||
static SDL_SpinLock tls_lock;
|
||||
static SDL_bool tls_being_created;
|
||||
static SDL_TLSID tls_errbuf;
|
||||
const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1;
|
||||
SDL_error *errbuf;
|
||||
|
||||
if (!tls_errbuf && !create) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* tls_being_created is there simply to prevent recursion if SDL_CreateTLS() 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_LockSpinlock(&tls_lock);
|
||||
if (!tls_errbuf) {
|
||||
SDL_TLSID slot;
|
||||
tls_being_created = SDL_TRUE;
|
||||
slot = SDL_CreateTLS();
|
||||
tls_being_created = SDL_FALSE;
|
||||
SDL_MemoryBarrierRelease();
|
||||
tls_errbuf = slot;
|
||||
}
|
||||
SDL_UnlockSpinlock(&tls_lock);
|
||||
}
|
||||
if (!tls_errbuf) {
|
||||
return SDL_GetStaticErrBuf();
|
||||
}
|
||||
|
||||
SDL_MemoryBarrierAcquire();
|
||||
errbuf = (SDL_error *)SDL_GetTLS(tls_errbuf);
|
||||
if (errbuf == ALLOCATION_IN_PROGRESS) {
|
||||
return SDL_GetStaticErrBuf();
|
||||
}
|
||||
errbuf = (SDL_error *)SDL_GetTLS(&tls_errbuf);
|
||||
if (!errbuf) {
|
||||
if (!create) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the original memory functions for this allocation because the lifetime
|
||||
* of the error buffer may span calls to SDL_SetMemoryFunctions() by the app
|
||||
*/
|
||||
@@ -304,17 +293,14 @@ SDL_error *SDL_GetErrBuf(SDL_bool create)
|
||||
SDL_free_func free_func;
|
||||
SDL_GetOriginalMemoryFunctions(NULL, NULL, &realloc_func, &free_func);
|
||||
|
||||
/* Mark that we're in the middle of allocating our buffer */
|
||||
SDL_SetTLS(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL);
|
||||
errbuf = (SDL_error *)realloc_func(NULL, sizeof(*errbuf));
|
||||
if (!errbuf) {
|
||||
SDL_SetTLS(tls_errbuf, NULL, NULL);
|
||||
return SDL_GetStaticErrBuf();
|
||||
}
|
||||
SDL_zerop(errbuf);
|
||||
errbuf->realloc_func = realloc_func;
|
||||
errbuf->free_func = free_func;
|
||||
SDL_SetTLS(tls_errbuf, errbuf, SDL_FreeErrBuf);
|
||||
SDL_SetTLS(&tls_errbuf, errbuf, SDL_FreeErrBuf);
|
||||
}
|
||||
return errbuf;
|
||||
#endif /* SDL_THREADS_DISABLED */
|
||||
|
||||
@@ -78,7 +78,7 @@ extern void SDL_RunThread(SDL_Thread *thread);
|
||||
/* This is the system-independent thread local storage structure */
|
||||
typedef struct
|
||||
{
|
||||
SDL_TLSID limit;
|
||||
int limit;
|
||||
struct
|
||||
{
|
||||
void *data;
|
||||
|
||||
@@ -36,14 +36,11 @@ HANDLE SDL_GetWaitableTimer()
|
||||
static SDL_TLSID TLS_timer_handle;
|
||||
HANDLE timer;
|
||||
|
||||
if (!TLS_timer_handle) {
|
||||
TLS_timer_handle = SDL_CreateTLS();
|
||||
}
|
||||
timer = SDL_GetTLS(TLS_timer_handle);
|
||||
timer = SDL_GetTLS(&TLS_timer_handle);
|
||||
if (!timer) {
|
||||
timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
||||
if (timer) {
|
||||
SDL_SetTLS(TLS_timer_handle, timer, SDL_CleanupWaitableTimer);
|
||||
SDL_SetTLS(&TLS_timer_handle, timer, SDL_CleanupWaitableTimer);
|
||||
}
|
||||
}
|
||||
return timer;
|
||||
|
||||
@@ -611,9 +611,6 @@ int SDL_VideoInit(const char *driver_name)
|
||||
_this->gl_config.dll_handle = NULL;
|
||||
SDL_GL_ResetAttributes();
|
||||
|
||||
_this->current_glwin_tls = SDL_CreateTLS();
|
||||
_this->current_glctx_tls = SDL_CreateTLS();
|
||||
|
||||
/* Initialize the video subsystem */
|
||||
if (_this->VideoInit(_this) < 0) {
|
||||
SDL_VideoQuit();
|
||||
@@ -4794,8 +4791,8 @@ SDL_GLContext SDL_GL_CreateContext(SDL_Window *window)
|
||||
if (ctx) {
|
||||
_this->current_glwin = window;
|
||||
_this->current_glctx = ctx;
|
||||
SDL_SetTLS(_this->current_glwin_tls, window, NULL);
|
||||
SDL_SetTLS(_this->current_glctx_tls, ctx, NULL);
|
||||
SDL_SetTLS(&_this->current_glwin_tls, window, NULL);
|
||||
SDL_SetTLS(&_this->current_glctx_tls, ctx, NULL);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -4830,8 +4827,8 @@ int SDL_GL_MakeCurrent(SDL_Window *window, SDL_GLContext context)
|
||||
if (retval == 0) {
|
||||
_this->current_glwin = window;
|
||||
_this->current_glctx = context;
|
||||
SDL_SetTLS(_this->current_glwin_tls, window, NULL);
|
||||
SDL_SetTLS(_this->current_glctx_tls, context, NULL);
|
||||
SDL_SetTLS(&_this->current_glwin_tls, window, NULL);
|
||||
SDL_SetTLS(&_this->current_glctx_tls, context, NULL);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -4842,7 +4839,7 @@ SDL_Window *SDL_GL_GetCurrentWindow(void)
|
||||
SDL_UninitializedVideo();
|
||||
return NULL;
|
||||
}
|
||||
return (SDL_Window *)SDL_GetTLS(_this->current_glwin_tls);
|
||||
return (SDL_Window *)SDL_GetTLS(&_this->current_glwin_tls);
|
||||
}
|
||||
|
||||
SDL_GLContext SDL_GL_GetCurrentContext(void)
|
||||
@@ -4851,7 +4848,7 @@ SDL_GLContext SDL_GL_GetCurrentContext(void)
|
||||
SDL_UninitializedVideo();
|
||||
return NULL;
|
||||
}
|
||||
return (SDL_GLContext)SDL_GetTLS(_this->current_glctx_tls);
|
||||
return (SDL_GLContext)SDL_GetTLS(&_this->current_glctx_tls);
|
||||
}
|
||||
|
||||
SDL_EGLDisplay SDL_EGL_GetCurrentEGLDisplay(void)
|
||||
|
||||
Reference in New Issue
Block a user