zenilib: zenilib/jni/external/sdl/src/thread/SDL_thread.c Source File

zenilib 0.5.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_thread.c
Go to the documentation of this file.
1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
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.
8
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:
12
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.
20 */
21 #include "SDL_config.h"
22
23 /* System independent thread management routines for SDL */
24
25 #include "SDL_thread.h"
26 #include "SDL_thread_c.h"
27 #include "SDL_systhread.h"
28 #include "../SDL_error_c.h"
29
30
31 SDL_TLSID
32 SDL_TLSCreate()
33 {
34 static SDL_atomic_t SDL_tls_id;
35 return SDL_AtomicIncRef(&SDL_tls_id)+1;
36 }
37
38 void *
39 SDL_TLSGet(SDL_TLSID id)
40 {
41 SDL_TLSData *storage;
42
43 storage = SDL_SYS_GetTLSData();
44 if (!storage || id == 0 || id > storage->limit) {
45 return NULL;
46 }
47 return storage->array[id-1].data;
48 }
49
50 int
51 SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void *))
52 {
53 SDL_TLSData *storage;
54
55 if (id == 0) {
56 return SDL_InvalidParamError("id");
57 }
58
59 storage = SDL_SYS_GetTLSData();
60 if (!storage || (id > storage->limit)) {
61 unsigned int i, oldlimit, newlimit;
62
63 oldlimit = storage ? storage->limit : 0;
64 newlimit = (id + TLS_ALLOC_CHUNKSIZE);
65 storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage)+(newlimit-1)*sizeof(storage->array[0]));
66 if (!storage) {
67 return SDL_OutOfMemory();
68 }
69 storage->limit = newlimit;
70 for (i = oldlimit; i < newlimit; ++i) {
71 storage->array[i].data = NULL;
72 storage->array[i].destructor = NULL;
73 }
74 if (SDL_SYS_SetTLSData(storage) != 0) {
75 return -1;
76 }
77 }
78
79 storage->array[id-1].data = SDL_const_cast(void*, value);
80 storage->array[id-1].destructor = destructor;
81 return 0;
82 }
83
84 static void
85 SDL_TLSCleanup()
86 {
87 SDL_TLSData *storage;
88
89 storage = SDL_SYS_GetTLSData();
90 if (storage) {
91 unsigned int i;
92 for (i = 0; i < storage->limit; ++i) {
93 if (storage->array[i].destructor) {
94 storage->array[i].destructor(storage->array[i].data);
95 }
96 }
97 SDL_SYS_SetTLSData(NULL);
98 SDL_free(storage);
99 }
100 }
101
102
103 /* This is a generic implementation of thread-local storage which doesn't
104 require additional OS support.
105
106 It is not especially efficient and doesn't clean up thread-local storage
107 as threads exit. If there is a real OS that doesn't support thread-local
108 storage this implementation should be improved to be production quality.
109 */
110
111 typedef struct SDL_TLSEntry {
112 SDL_threadID thread;
113 SDL_TLSData *storage;
114 struct SDL_TLSEntry *next;
115 } SDL_TLSEntry;
116
117 static SDL_mutex *SDL_generic_TLS_mutex;
118 static SDL_TLSEntry *SDL_generic_TLS;
119
120
121 SDL_TLSData *
122 SDL_Generic_GetTLSData()
123 {
124 SDL_threadID thread = SDL_ThreadID();
125 SDL_TLSEntry *entry;
126 SDL_TLSData *storage = NULL;
127
128 #if !SDL_THREADS_DISABLED
129 if (!SDL_generic_TLS_mutex) {
130 static SDL_SpinLock tls_lock;
131 SDL_AtomicLock(&tls_lock);
132 if (!SDL_generic_TLS_mutex) {
133 SDL_mutex *mutex = SDL_CreateMutex();
134 SDL_MemoryBarrierRelease();
135 SDL_generic_TLS_mutex = mutex;
136 if (!SDL_generic_TLS_mutex) {
137 SDL_AtomicUnlock(&tls_lock);
138 return NULL;
139 }
140 }
141 SDL_AtomicUnlock(&tls_lock);
142 }
143 #endif /* SDL_THREADS_DISABLED */
144
145 SDL_MemoryBarrierAcquire();
146 SDL_LockMutex(SDL_generic_TLS_mutex);
147 for (entry = SDL_generic_TLS; entry; entry = entry->next) {
148 if (entry->thread == thread) {
149 storage = entry->storage;
150 break;
151 }
152 }
153 #if !SDL_THREADS_DISABLED
154 SDL_UnlockMutex(SDL_generic_TLS_mutex);
155 #endif
156
157 return storage;
158 }
159
160 int
161 SDL_Generic_SetTLSData(SDL_TLSData *storage)
162 {
163 SDL_threadID thread = SDL_ThreadID();
164 SDL_TLSEntry *prev, *entry;
165
166 /* SDL_Generic_GetTLSData() is always called first, so we can assume SDL_generic_TLS_mutex */
167 SDL_LockMutex(SDL_generic_TLS_mutex);
168 prev = NULL;
169 for (entry = SDL_generic_TLS; entry; entry = entry->next) {
170 if (entry->thread == thread) {
171 if (storage) {
172 entry->storage = storage;
173 } else {
174 if (prev) {
175 prev->next = entry->next;
176 } else {
177 SDL_generic_TLS = entry->next;
178 }
179 SDL_free(entry);
180 }
181 break;
182 }
183 prev = entry;
184 }
185 if (!entry) {
186 entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
187 if (entry) {
188 entry->thread = thread;
189 entry->storage = storage;
190 entry->next = SDL_generic_TLS;
191 SDL_generic_TLS = entry;
192 }
193 }
194 SDL_UnlockMutex(SDL_generic_TLS_mutex);
195
196 if (!entry) {
197 return SDL_OutOfMemory();
198 }
199 return 0;
200 }
201
202 /* Routine to get the thread-specific error variable */
203 SDL_error *
204 SDL_GetErrBuf(void)
205 {
206 static SDL_SpinLock tls_lock;
207 static SDL_bool tls_being_created;
208 static SDL_TLSID tls_errbuf;
209 static SDL_error SDL_global_errbuf;
210 const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1;
211 SDL_error *errbuf;
212
213 /* tls_being_created is there simply to prevent recursion if SDL_TLSCreate() fails.
214 It also means it's possible for another thread to also use SDL_global_errbuf,
215 but that's very unlikely and hopefully won't cause issues.
216 */
217 if (!tls_errbuf && !tls_being_created) {
218 SDL_AtomicLock(&tls_lock);
219 if (!tls_errbuf) {
220 SDL_TLSID slot;
221 tls_being_created = SDL_TRUE;
222 slot = SDL_TLSCreate();
223 tls_being_created = SDL_FALSE;
224 SDL_MemoryBarrierRelease();
225 tls_errbuf = slot;
226 }
227 SDL_AtomicUnlock(&tls_lock);
228 }
229 if (!tls_errbuf) {
230 return &SDL_global_errbuf;
231 }
232
233 SDL_MemoryBarrierAcquire();
234 errbuf = (SDL_error *)SDL_TLSGet(tls_errbuf);
235 if (errbuf == ALLOCATION_IN_PROGRESS) {
236 return &SDL_global_errbuf;
237 }
238 if (!errbuf) {
239 /* Mark that we're in the middle of allocating our buffer */
240 SDL_TLSSet(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL);
241 errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
242 if (!errbuf) {
243 SDL_TLSSet(tls_errbuf, NULL, NULL);
244 return &SDL_global_errbuf;
245 }
246 SDL_zerop(errbuf);
247 SDL_TLSSet(tls_errbuf, errbuf, SDL_free);
248 }
249 return errbuf;
250 }
251
252
253 /* Arguments and callback to setup and run the user thread function */
254 typedef struct
255 {
256 int (SDLCALL * func) (void *);
257 void *data;
258 SDL_Thread *info;
259 SDL_sem *wait;
260 } thread_args;
261
262 void
263 SDL_RunThread(void *data)
264 {
265 thread_args *args = (thread_args *) data;
266 int (SDLCALL * userfunc) (void *) = args->func;
267 void *userdata = args->data;
268 int *statusloc = &args->info->status;
269
270 /* Perform any system-dependent setup - this function may not fail */
271 SDL_SYS_SetupThread(args->info->name);
272
273 /* Get the thread id */
274 args->info->threadid = SDL_ThreadID();
275
276 /* Wake up the parent thread */
277 SDL_SemPost(args->wait);
278
279 /* Run the function */
280 *statusloc = userfunc(userdata);
281
282 /* Clean up thread-local storage */
283 SDL_TLSCleanup();
284 }
285
286 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
287 #undef SDL_CreateThread
288 DECLSPEC SDL_Thread *SDLCALL
289 SDL_CreateThread(int (SDLCALL * fn) (void *),
290 const char *name, void *data,
291 pfnSDL_CurrentBeginThread pfnBeginThread,
292 pfnSDL_CurrentEndThread pfnEndThread)
293 #else
294 DECLSPEC SDL_Thread *SDLCALL
295 SDL_CreateThread(int (SDLCALL * fn) (void *),
296 const char *name, void *data)
297 #endif
298 {
299 SDL_Thread *thread;
300 thread_args *args;
301 int ret;
302
303 /* Allocate memory for the thread info structure */
304 thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
305 if (thread == NULL) {
306 SDL_OutOfMemory();
307 return (NULL);
308 }
309 SDL_memset(thread, 0, (sizeof *thread));
310 thread->status = -1;
311
312 /* Set up the arguments for the thread */
313 if (name != NULL) {
314 thread->name = SDL_strdup(name);
315 if (thread->name == NULL) {
316 SDL_OutOfMemory();
317 SDL_free(thread);
318 return (NULL);
319 }
320 }
321
322 /* Set up the arguments for the thread */
323 args = (thread_args *) SDL_malloc(sizeof(*args));
324 if (args == NULL) {
325 SDL_OutOfMemory();
326 if (thread->name) {
327 SDL_free(thread->name);
328 }
329 SDL_free(thread);
330 return (NULL);
331 }
332 args->func = fn;
333 args->data = data;
334 args->info = thread;
335 args->wait = SDL_CreateSemaphore(0);
336 if (args->wait == NULL) {
337 if (thread->name) {
338 SDL_free(thread->name);
339 }
340 SDL_free(thread);
341 SDL_free(args);
342 return (NULL);
343 }
344
345 /* Create the thread and go! */
346 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
347 ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
348 #else
349 ret = SDL_SYS_CreateThread(thread, args);
350 #endif
351 if (ret >= 0) {
352 /* Wait for the thread function to use arguments */
353 SDL_SemWait(args->wait);
354 } else {
355 /* Oops, failed. Gotta free everything */
356 if (thread->name) {
357 SDL_free(thread->name);
358 }
359 SDL_free(thread);
360 thread = NULL;
361 }
362 SDL_DestroySemaphore(args->wait);
363 SDL_free(args);
364
365 /* Everything is running now */
366 return (thread);
367 }
368
369 SDL_threadID
370 SDL_GetThreadID(SDL_Thread * thread)
371 {
372 SDL_threadID id;
373
374 if (thread) {
375 id = thread->threadid;
376 } else {
377 id = SDL_ThreadID();
378 }
379 return id;
380 }
381
382 const char *
383 SDL_GetThreadName(SDL_Thread * thread)
384 {
385 if (thread) {
386 return thread->name;
387 } else {
388 return NULL;
389 }
390 }
391
392 int
393 SDL_SetThreadPriority(SDL_ThreadPriority priority)
394 {
395 return SDL_SYS_SetThreadPriority(priority);
396 }
397
398 void
399 SDL_WaitThread(SDL_Thread * thread, int *status)
400 {
401 if (thread) {
402 SDL_SYS_WaitThread(thread);
403 if (status) {
404 *status = thread->status;
405 }
406 if (thread->name) {
407 SDL_free(thread->name);
408 }
409 SDL_free(thread);
410 }
411 }
412
413 /* vi: set ts=4 sw=4 expandtab: */
SDL_CreateSemaphore
DECLSPEC SDL_sem *SDLCALL SDL_CreateSemaphore(Uint32 initial_value)
Definition: SDL_syssem.c:85
SDL_generic_TLS_mutex
static SDL_mutex * SDL_generic_TLS_mutex
Definition: SDL_thread.c:117
SDL_Thread::name
char * name
Definition: SDL_thread_c.h:54
SDL_ThreadID
DECLSPEC SDL_threadID SDLCALL SDL_ThreadID(void)
Definition: SDL_systhread.c:48
SDL_AtomicUnlock
DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock)
Unlock a spin lock by setting it to 0. Always returns immediately.
Definition: SDL_spinlock.c:109
SDL_threadID
unsigned long SDL_threadID
Definition: SDL_thread.h:49
SDL_sem
struct SDL_semaphore SDL_sem
Definition: SDL_mutex.h:107
NULL
#define NULL
Definition: ftobjs.h:61
SDL_Generic_GetTLSData
SDL_TLSData * SDL_Generic_GetTLSData()
Definition: SDL_thread.c:122
SDL_MemoryBarrierRelease
#define SDL_MemoryBarrierRelease()
Definition: SDL_atomic.h:180
SDL_GetThreadID
DECLSPEC SDL_threadID SDLCALL SDL_GetThreadID(SDL_Thread *thread)
Definition: SDL_thread.c:370
SDL_atomic_t
A type representing an atomic integer value. It is a struct so people don&#39;t accidentally use numeric ...
Definition: SDL_atomic.h:233
SDL_GetThreadName
DECLSPEC const char *SDLCALL SDL_GetThreadName(SDL_Thread *thread)
Definition: SDL_thread.c:383
TLS_ALLOC_CHUNKSIZE
#define TLS_ALLOC_CHUNKSIZE
Definition: SDL_thread_c.h:71
SDL_TLSData::data
void * data
Definition: SDL_thread_c.h:65
SDL_LockMutex
DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:73
SDL_Generic_SetTLSData
int SDL_Generic_SetTLSData(SDL_TLSData *storage)
Definition: SDL_thread.c:161
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:116
SDL_SemWait
DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem)
Definition: SDL_syssem.c:180
SDL_TRUE
Definition: SDL_stdinc.h:119
SDL_CreateMutex
DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void)
Definition: SDL_sysmutex.c:38
SDL_realloc
DECLSPEC void *SDLCALL SDL_realloc(void *mem, size_t size)
SDL_free
DECLSPEC void SDLCALL SDL_free(void *mem)
SDL_TLSData
Definition: SDL_thread_c.h:62
SDL_TLSCreate
DECLSPEC SDL_TLSID SDLCALL SDL_TLSCreate(void)
Create an identifier that is globally visible to all threads but refers to data that is thread-specif...
Definition: SDL_thread.c:32
SDL_TLSData::limit
unsigned int limit
Definition: SDL_thread_c.h:63
DECLSPEC
#define DECLSPEC
Definition: begin_code.h:62
name
EGLImageKHR EGLint * name
Definition: eglext.h:284
SDL_error
Definition: SDL_error_c.h:33
SDL_SYS_SetTLSData
int SDL_SYS_SetTLSData(SDL_TLSData *data)
Definition: SDL_systls.c:33
SDL_Thread::threadid
SDL_threadID threadid
Definition: SDL_thread_c.h:50
SDL_InvalidParamError
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
SDLCALL
#define SDLCALL
Definition: begin_code.h:72
SDL_systhread.h
SDL_const_cast
#define SDL_const_cast(type, expression)
Definition: SDL_stdinc.h:100
SDL_SYS_GetTLSData
SDL_TLSData * SDL_SYS_GetTLSData()
Definition: SDL_systls.c:27
SDL_FALSE
Definition: SDL_stdinc.h:118
id
GLuint id
Definition: gl2ext.h:1142
func
GLenum func
Definition: SDL_opengl.h:5654
SDL_Thread::status
int status
Definition: SDL_thread_c.h:52
SDL_SYS_CreateThread
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
Definition: SDL_systhread.c:42
SDL_GetErrBuf
SDL_error * SDL_GetErrBuf(void)
Definition: SDL_thread.c:204
SDL_MemoryBarrierAcquire
#define SDL_MemoryBarrierAcquire()
Definition: SDL_atomic.h:181
SDL_config.h
SDL_UnlockMutex
DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:160
ret
ret
Definition: glew_str_glx.c:2
SDL_TLSData::destructor
void(* destructor)(void *)
Definition: SDL_thread_c.h:66
SDL_WaitThread
DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread *thread, int *status)
Definition: SDL_thread.c:399
SDL_SYS_WaitThread
void SDL_SYS_WaitThread(SDL_Thread *thread)
Definition: SDL_systhread.c:60
SDL_AtomicLock
DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock)
Lock a spin lock by setting it to a non-zero value.
Definition: SDL_spinlock.c:100
SDL_TLSEntry
struct SDL_TLSEntry SDL_TLSEntry
int
int
Definition: SDL_systhread.c:37
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
SDL_strdup
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
SDL_SYS_SetThreadPriority
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_systhread.c:54
SDL_thread_c.h
SDL_memset
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
SDL_malloc
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
SDL_TLSCleanup
static void SDL_TLSCleanup()
Definition: SDL_thread.c:85
SDL_AtomicIncRef
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:297
SDL_DestroySemaphore
DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem)
Definition: SDL_syssem.c:111
SDL_CreateThread
DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data)
thread
static SDL_Thread * thread
Definition: SDL_sysjoystick.c:41
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_mutex
struct SDL_mutex SDL_mutex
Definition: SDL_mutex.h:59
value
EGLSurface EGLint void ** value
Definition: eglext.h:301
SDL_generic_TLS
static SDL_TLSEntry * SDL_generic_TLS
Definition: SDL_thread.c:118
SDL_TLSSet
DECLSPEC int SDLCALL SDL_TLSSet(SDL_TLSID id, const void *value, void(*destructor)(void *))
Set the value associated with a thread local storage ID for the current thread.
Definition: SDL_thread.c:51
SDL_RunThread
void SDL_RunThread(void *data)
Definition: SDL_thread.c:263
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:255
SDL_SYS_SetupThread
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
SDL_Thread
Definition: SDL_thread_c.h:48
SDL_ThreadPriority
SDL_ThreadPriority
Definition: SDL_thread.h:59
SDL_SpinLock
int SDL_SpinLock
Definition: SDL_atomic.h:96
i
int i
Definition: pngrutil.c:1377
SDL_SetThreadPriority
DECLSPEC int SDLCALL SDL_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_thread.c:393
SDL_SemPost
DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem)
Definition: SDL_syssem.c:200
SDL_TLSData::array
struct SDL_TLSData::@84 array[1]
SDL_TLSGet
DECLSPEC void *SDLCALL SDL_TLSGet(SDL_TLSID id)
Get the value associated with a thread local storage ID for the current thread.
Definition: SDL_thread.c:39
SDL_TLSID
unsigned int SDL_TLSID
Definition: SDL_thread.h:52