zenilib  0.5.3.0
 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 
33 {
34  static SDL_atomic_t SDL_tls_id;
35  return SDL_AtomicIncRef(&SDL_tls_id)+1;
36 }
37 
38 void *
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
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  }
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 {
113  SDL_TLSData *storage;
114  struct SDL_TLSEntry *next;
115 } SDL_TLSEntry;
116 
119 
120 
121 SDL_TLSData *
123 {
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();
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 
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
162 {
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 *
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;
225  tls_errbuf = slot;
226  }
227  SDL_AtomicUnlock(&tls_lock);
228  }
229  if (!tls_errbuf) {
230  return &SDL_global_errbuf;
231  }
232 
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
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
289 SDL_CreateThread(int (SDLCALL * fn) (void *),
290  const char *name, void *data,
291  pfnSDL_CurrentBeginThread pfnBeginThread,
292  pfnSDL_CurrentEndThread pfnEndThread)
293 #else
295 SDL_CreateThread(int (SDLCALL * fn) (void *),
296  const char *name, void *data)
297 #endif
298 {
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 
371 {
373 
374  if (thread) {
375  id = thread->threadid;
376  } else {
377  id = SDL_ThreadID();
378  }
379  return id;
380 }
381 
382 const char *
384 {
385  if (thread) {
386  return thread->name;
387  } else {
388  return NULL;
389  }
390 }
391 
392 int
394 {
395  return SDL_SYS_SetThreadPriority(priority);
396 }
397 
398 void
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: */
DECLSPEC SDL_sem *SDLCALL SDL_CreateSemaphore(Uint32 initial_value)
Definition: SDL_syssem.c:85
static SDL_mutex * SDL_generic_TLS_mutex
Definition: SDL_thread.c:117
char * name
Definition: SDL_thread_c.h:54
DECLSPEC SDL_threadID SDLCALL SDL_ThreadID(void)
Definition: SDL_systhread.c:48
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
unsigned long SDL_threadID
Definition: SDL_thread.h:49
struct SDL_semaphore SDL_sem
Definition: SDL_mutex.h:107
#define NULL
Definition: ftobjs.h:61
SDL_TLSData * SDL_Generic_GetTLSData()
Definition: SDL_thread.c:122
#define SDL_MemoryBarrierRelease()
Definition: SDL_atomic.h:180
DECLSPEC SDL_threadID SDLCALL SDL_GetThreadID(SDL_Thread *thread)
Definition: SDL_thread.c:370
A type representing an atomic integer value. It is a struct so people don&#39;t accidentally use numeric ...
Definition: SDL_atomic.h:233
DECLSPEC const char *SDLCALL SDL_GetThreadName(SDL_Thread *thread)
Definition: SDL_thread.c:383
#define TLS_ALLOC_CHUNKSIZE
Definition: SDL_thread_c.h:71
void * data
Definition: SDL_thread_c.h:65
DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:73
int SDL_Generic_SetTLSData(SDL_TLSData *storage)
Definition: SDL_thread.c:161
SDL_bool
Definition: SDL_stdinc.h:116
DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem)
Definition: SDL_syssem.c:180
DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void)
Definition: SDL_sysmutex.c:38
DECLSPEC void *SDLCALL SDL_realloc(void *mem, size_t size)
DECLSPEC void SDLCALL SDL_free(void *mem)
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
unsigned int limit
Definition: SDL_thread_c.h:63
#define DECLSPEC
Definition: begin_code.h:62
EGLImageKHR EGLint * name
Definition: eglext.h:284
int SDL_SYS_SetTLSData(SDL_TLSData *data)
Definition: SDL_systls.c:33
SDL_threadID threadid
Definition: SDL_thread_c.h:50
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
#define SDLCALL
Definition: begin_code.h:72
#define SDL_const_cast(type, expression)
Definition: SDL_stdinc.h:100
SDL_TLSData * SDL_SYS_GetTLSData()
Definition: SDL_systls.c:27
GLuint id
Definition: gl2ext.h:1142
GLenum func
Definition: SDL_opengl.h:5654
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
Definition: SDL_systhread.c:42
SDL_error * SDL_GetErrBuf(void)
Definition: SDL_thread.c:204
#define SDL_MemoryBarrierAcquire()
Definition: SDL_atomic.h:181
DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex *mutex)
Definition: SDL_sysmutex.c:160
ret
Definition: glew_str_glx.c:2
void(* destructor)(void *)
Definition: SDL_thread_c.h:66
DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread *thread, int *status)
Definition: SDL_thread.c:399
void SDL_SYS_WaitThread(SDL_Thread *thread)
Definition: SDL_systhread.c:60
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
struct SDL_TLSEntry SDL_TLSEntry
int
Definition: SDL_systhread.c:37
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_systhread.c:54
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
static void SDL_TLSCleanup()
Definition: SDL_thread.c:85
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:297
DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem)
Definition: SDL_syssem.c:111
DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data)
static SDL_Thread * thread
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
struct SDL_mutex SDL_mutex
Definition: SDL_mutex.h:59
EGLSurface EGLint void ** value
Definition: eglext.h:301
static SDL_TLSEntry * SDL_generic_TLS
Definition: SDL_thread.c:118
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
void SDL_RunThread(void *data)
Definition: SDL_thread.c:263
#define SDL_zerop(x)
Definition: SDL_stdinc.h:255
void SDL_SYS_SetupThread(const char *name)
Definition: SDL_systhread.c:42
SDL_ThreadPriority
Definition: SDL_thread.h:59
int SDL_SpinLock
Definition: SDL_atomic.h:96
int i
Definition: pngrutil.c:1377
DECLSPEC int SDLCALL SDL_SetThreadPriority(SDL_ThreadPriority priority)
Definition: SDL_thread.c:393
DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem)
Definition: SDL_syssem.c:200
struct SDL_TLSData::@84 array[1]
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
unsigned int SDL_TLSID
Definition: SDL_thread.h:52