/* 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; }
SDL_TLSData * SDL_Generic_GetTLSData() { 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; }
SDL_TLSData * SDL_SYS_GetTLSData() { 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); }
SDL_TLSData * SDL_SYS_GetTLSData() { 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); }