Fixed empty parameter list in signatures of internal functions.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../SDL_internal.h"
23 /* System independent thread management routines for SDL */
25 #include "SDL_assert.h"
26 #include "SDL_thread.h"
27 #include "SDL_thread_c.h"
28 #include "SDL_systhread.h"
29 #include "SDL_hints.h"
30 #include "../SDL_error_c.h"
36 static SDL_atomic_t SDL_tls_id;
37 return SDL_AtomicIncRef(&SDL_tls_id)+1;
41 SDL_TLSGet(SDL_TLSID id)
45 storage = SDL_SYS_GetTLSData();
46 if (!storage || id == 0 || id > storage->limit) {
49 return storage->array[id-1].data;
53 SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void *))
58 return SDL_InvalidParamError("id");
61 storage = SDL_SYS_GetTLSData();
62 if (!storage || (id > storage->limit)) {
63 unsigned int i, oldlimit, newlimit;
65 oldlimit = storage ? storage->limit : 0;
66 newlimit = (id + TLS_ALLOC_CHUNKSIZE);
67 storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage)+(newlimit-1)*sizeof(storage->array[0]));
69 return SDL_OutOfMemory();
71 storage->limit = newlimit;
72 for (i = oldlimit; i < newlimit; ++i) {
73 storage->array[i].data = NULL;
74 storage->array[i].destructor = NULL;
76 if (SDL_SYS_SetTLSData(storage) != 0) {
81 storage->array[id-1].data = SDL_const_cast(void*, value);
82 storage->array[id-1].destructor = destructor;
91 storage = SDL_SYS_GetTLSData();
94 for (i = 0; i < storage->limit; ++i) {
95 if (storage->array[i].destructor) {
96 storage->array[i].destructor(storage->array[i].data);
99 SDL_SYS_SetTLSData(NULL);
105 /* This is a generic implementation of thread-local storage which doesn't
106 require additional OS support.
108 It is not especially efficient and doesn't clean up thread-local storage
109 as threads exit. If there is a real OS that doesn't support thread-local
110 storage this implementation should be improved to be production quality.
113 typedef struct SDL_TLSEntry {
115 SDL_TLSData *storage;
116 struct SDL_TLSEntry *next;
119 static SDL_mutex *SDL_generic_TLS_mutex;
120 static SDL_TLSEntry *SDL_generic_TLS;
124 SDL_Generic_GetTLSData(void)
126 SDL_threadID thread = SDL_ThreadID();
128 SDL_TLSData *storage = NULL;
130 #if !SDL_THREADS_DISABLED
131 if (!SDL_generic_TLS_mutex) {
132 static SDL_SpinLock tls_lock;
133 SDL_AtomicLock(&tls_lock);
134 if (!SDL_generic_TLS_mutex) {
135 SDL_mutex *mutex = SDL_CreateMutex();
136 SDL_MemoryBarrierRelease();
137 SDL_generic_TLS_mutex = mutex;
138 if (!SDL_generic_TLS_mutex) {
139 SDL_AtomicUnlock(&tls_lock);
143 SDL_AtomicUnlock(&tls_lock);
145 #endif /* SDL_THREADS_DISABLED */
147 SDL_MemoryBarrierAcquire();
148 SDL_LockMutex(SDL_generic_TLS_mutex);
149 for (entry = SDL_generic_TLS; entry; entry = entry->next) {
150 if (entry->thread == thread) {
151 storage = entry->storage;
155 #if !SDL_THREADS_DISABLED
156 SDL_UnlockMutex(SDL_generic_TLS_mutex);
163 SDL_Generic_SetTLSData(SDL_TLSData *storage)
165 SDL_threadID thread = SDL_ThreadID();
166 SDL_TLSEntry *prev, *entry;
168 /* SDL_Generic_GetTLSData() is always called first, so we can assume SDL_generic_TLS_mutex */
169 SDL_LockMutex(SDL_generic_TLS_mutex);
171 for (entry = SDL_generic_TLS; entry; entry = entry->next) {
172 if (entry->thread == thread) {
174 entry->storage = storage;
177 prev->next = entry->next;
179 SDL_generic_TLS = entry->next;
188 entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
190 entry->thread = thread;
191 entry->storage = storage;
192 entry->next = SDL_generic_TLS;
193 SDL_generic_TLS = entry;
196 SDL_UnlockMutex(SDL_generic_TLS_mutex);
199 return SDL_OutOfMemory();
204 /* Routine to get the thread-specific error variable */
208 static SDL_SpinLock tls_lock;
209 static SDL_bool tls_being_created;
210 static SDL_TLSID tls_errbuf;
211 static SDL_error SDL_global_errbuf;
212 const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1;
215 /* tls_being_created is there simply to prevent recursion if SDL_TLSCreate() fails.
216 It also means it's possible for another thread to also use SDL_global_errbuf,
217 but that's very unlikely and hopefully won't cause issues.
219 if (!tls_errbuf && !tls_being_created) {
220 SDL_AtomicLock(&tls_lock);
223 tls_being_created = SDL_TRUE;
224 slot = SDL_TLSCreate();
225 tls_being_created = SDL_FALSE;
226 SDL_MemoryBarrierRelease();
229 SDL_AtomicUnlock(&tls_lock);
232 return &SDL_global_errbuf;
235 SDL_MemoryBarrierAcquire();
236 errbuf = (SDL_error *)SDL_TLSGet(tls_errbuf);
237 if (errbuf == ALLOCATION_IN_PROGRESS) {
238 return &SDL_global_errbuf;
241 /* Mark that we're in the middle of allocating our buffer */
242 SDL_TLSSet(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL);
243 errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
245 SDL_TLSSet(tls_errbuf, NULL, NULL);
246 return &SDL_global_errbuf;
249 SDL_TLSSet(tls_errbuf, errbuf, SDL_free);
255 /* Arguments and callback to setup and run the user thread function */
258 int (SDLCALL * func) (void *);
265 SDL_RunThread(void *data)
267 thread_args *args = (thread_args *) data;
268 int (SDLCALL * userfunc) (void *) = args->func;
269 void *userdata = args->data;
270 SDL_Thread *thread = args->info;
271 int *statusloc = &thread->status;
273 /* Perform any system-dependent setup - this function may not fail */
274 SDL_SYS_SetupThread(thread->name);
276 /* Get the thread id */
277 thread->threadid = SDL_ThreadID();
279 /* Wake up the parent thread */
280 SDL_SemPost(args->wait);
282 /* Run the function */
283 *statusloc = userfunc(userdata);
285 /* Clean up thread-local storage */
288 /* Mark us as ready to be joined (or detached) */
289 if (!SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_ZOMBIE)) {
290 /* Clean up if something already detached us. */
291 if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_DETACHED, SDL_THREAD_STATE_CLEANED)) {
293 SDL_free(thread->name);
300 #ifdef SDL_CreateThread
301 #undef SDL_CreateThread
304 #define SDL_CreateThread SDL_CreateThread_REAL
307 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
309 SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
310 const char *name, const size_t stacksize, void *data,
311 pfnSDL_CurrentBeginThread pfnBeginThread,
312 pfnSDL_CurrentEndThread pfnEndThread)
315 SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
316 const char *name, const size_t stacksize, void *data)
323 /* Allocate memory for the thread info structure */
324 thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
325 if (thread == NULL) {
331 SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
333 /* Set up the arguments for the thread */
335 thread->name = SDL_strdup(name);
336 if (thread->name == NULL) {
343 /* Set up the arguments for the thread */
344 args = (thread_args *) SDL_malloc(sizeof(*args));
348 SDL_free(thread->name);
356 args->wait = SDL_CreateSemaphore(0);
357 if (args->wait == NULL) {
359 SDL_free(thread->name);
366 thread->stacksize = stacksize;
368 /* Create the thread and go! */
369 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
370 ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
372 ret = SDL_SYS_CreateThread(thread, args);
375 /* Wait for the thread function to use arguments */
376 SDL_SemWait(args->wait);
378 /* Oops, failed. Gotta free everything */
380 SDL_free(thread->name);
385 SDL_DestroySemaphore(args->wait);
388 /* Everything is running now */
392 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
393 DECLSPEC SDL_Thread *SDLCALL
394 SDL_CreateThread(int (SDLCALL * fn) (void *),
395 const char *name, void *data,
396 pfnSDL_CurrentBeginThread pfnBeginThread,
397 pfnSDL_CurrentEndThread pfnEndThread)
399 DECLSPEC SDL_Thread *SDLCALL
400 SDL_CreateThread(int (SDLCALL * fn) (void *),
401 const char *name, void *data)
404 /* !!! FIXME: in 2.1, just make stackhint part of the usual API. */
405 const char *stackhint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE);
406 size_t stacksize = 0;
408 /* If the SDL_HINT_THREAD_STACK_SIZE exists, use it */
409 if (stackhint != NULL) {
411 const Sint64 hintval = SDL_strtoll(stackhint, &endp, 10);
412 if ((*stackhint != '\0') && (*endp == '\0')) { /* a valid number? */
413 if (hintval > 0) { /* reject bogus values. */
414 stacksize = (size_t) hintval;
419 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
420 return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, pfnBeginThread, pfnEndThread);
422 return SDL_CreateThreadWithStackSize(fn, name, stacksize, data);
427 SDL_CreateThreadInternal(int (SDLCALL * fn) (void *), const char *name,
428 const size_t stacksize, void *data) {
429 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
430 return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, NULL, NULL);
432 return SDL_CreateThreadWithStackSize(fn, name, stacksize, data);
437 SDL_GetThreadID(SDL_Thread * thread)
442 id = thread->threadid;
450 SDL_GetThreadName(SDL_Thread * thread)
460 SDL_SetThreadPriority(SDL_ThreadPriority priority)
462 return SDL_SYS_SetThreadPriority(priority);
466 SDL_WaitThread(SDL_Thread * thread, int *status)
469 SDL_SYS_WaitThread(thread);
471 *status = thread->status;
474 SDL_free(thread->name);
481 SDL_DetachThread(SDL_Thread * thread)
487 /* Grab dibs if the state is alive+joinable. */
488 if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_DETACHED)) {
489 SDL_SYS_DetachThread(thread);
491 /* all other states are pretty final, see where we landed. */
492 const int thread_state = SDL_AtomicGet(&thread->state);
493 if ((thread_state == SDL_THREAD_STATE_DETACHED) || (thread_state == SDL_THREAD_STATE_CLEANED)) {
494 return; /* already detached (you shouldn't call this twice!) */
495 } else if (thread_state == SDL_THREAD_STATE_ZOMBIE) {
496 SDL_WaitThread(thread, NULL); /* already done, clean it up. */
498 SDL_assert(0 && "Unexpected thread state");
503 /* vi: set ts=4 sw=4 expandtab: */