slouken@0
|
1 |
/*
|
slouken@5535
|
2 |
Simple DirectMedia Layer
|
slouken@9619
|
3 |
Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
|
slouken@0
|
4 |
|
slouken@5535
|
5 |
This software is provided 'as-is', without any express or implied
|
slouken@5535
|
6 |
warranty. In no event will the authors be held liable for any damages
|
slouken@5535
|
7 |
arising from the use of this software.
|
slouken@0
|
8 |
|
slouken@5535
|
9 |
Permission is granted to anyone to use this software for any purpose,
|
slouken@5535
|
10 |
including commercial applications, and to alter it and redistribute it
|
slouken@5535
|
11 |
freely, subject to the following restrictions:
|
slouken@0
|
12 |
|
slouken@5535
|
13 |
1. The origin of this software must not be misrepresented; you must not
|
slouken@5535
|
14 |
claim that you wrote the original software. If you use this software
|
slouken@5535
|
15 |
in a product, an acknowledgment in the product documentation would be
|
slouken@5535
|
16 |
appreciated but is not required.
|
slouken@5535
|
17 |
2. Altered source versions must be plainly marked as such, and must not be
|
slouken@5535
|
18 |
misrepresented as being the original software.
|
slouken@5535
|
19 |
3. This notice may not be removed or altered from any source distribution.
|
slouken@0
|
20 |
*/
|
icculus@8093
|
21 |
#include "../SDL_internal.h"
|
slouken@0
|
22 |
|
slouken@0
|
23 |
/* System independent thread management routines for SDL */
|
slouken@0
|
24 |
|
icculus@7978
|
25 |
#include "SDL_assert.h"
|
slouken@0
|
26 |
#include "SDL_thread.h"
|
slouken@0
|
27 |
#include "SDL_thread_c.h"
|
slouken@0
|
28 |
#include "SDL_systhread.h"
|
slouken@6044
|
29 |
#include "../SDL_error_c.h"
|
slouken@0
|
30 |
|
slouken@0
|
31 |
|
slouken@7393
|
32 |
SDL_TLSID
|
slouken@7393
|
33 |
SDL_TLSCreate()
|
slouken@7393
|
34 |
{
|
slouken@7393
|
35 |
static SDL_atomic_t SDL_tls_id;
|
slouken@7393
|
36 |
return SDL_AtomicIncRef(&SDL_tls_id)+1;
|
slouken@7393
|
37 |
}
|
slouken@7393
|
38 |
|
slouken@7393
|
39 |
void *
|
slouken@7393
|
40 |
SDL_TLSGet(SDL_TLSID id)
|
slouken@7393
|
41 |
{
|
slouken@7393
|
42 |
SDL_TLSData *storage;
|
slouken@7393
|
43 |
|
slouken@7393
|
44 |
storage = SDL_SYS_GetTLSData();
|
slouken@7393
|
45 |
if (!storage || id == 0 || id > storage->limit) {
|
slouken@7393
|
46 |
return NULL;
|
slouken@7393
|
47 |
}
|
slouken@7393
|
48 |
return storage->array[id-1].data;
|
slouken@7393
|
49 |
}
|
slouken@7393
|
50 |
|
slouken@7393
|
51 |
int
|
slouken@7393
|
52 |
SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void *))
|
slouken@7393
|
53 |
{
|
slouken@7393
|
54 |
SDL_TLSData *storage;
|
slouken@7393
|
55 |
|
slouken@7393
|
56 |
if (id == 0) {
|
slouken@7393
|
57 |
return SDL_InvalidParamError("id");
|
slouken@7393
|
58 |
}
|
slouken@7393
|
59 |
|
slouken@7393
|
60 |
storage = SDL_SYS_GetTLSData();
|
icculus@7482
|
61 |
if (!storage || (id > storage->limit)) {
|
icculus@7482
|
62 |
unsigned int i, oldlimit, newlimit;
|
slouken@7393
|
63 |
|
slouken@7393
|
64 |
oldlimit = storage ? storage->limit : 0;
|
slouken@7393
|
65 |
newlimit = (id + TLS_ALLOC_CHUNKSIZE);
|
slouken@7393
|
66 |
storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage)+(newlimit-1)*sizeof(storage->array[0]));
|
slouken@7393
|
67 |
if (!storage) {
|
slouken@7393
|
68 |
return SDL_OutOfMemory();
|
slouken@7393
|
69 |
}
|
slouken@7393
|
70 |
storage->limit = newlimit;
|
slouken@7393
|
71 |
for (i = oldlimit; i < newlimit; ++i) {
|
slouken@7393
|
72 |
storage->array[i].data = NULL;
|
slouken@7393
|
73 |
storage->array[i].destructor = NULL;
|
slouken@7393
|
74 |
}
|
slouken@7393
|
75 |
if (SDL_SYS_SetTLSData(storage) != 0) {
|
slouken@7393
|
76 |
return -1;
|
slouken@7393
|
77 |
}
|
slouken@7393
|
78 |
}
|
slouken@7393
|
79 |
|
slouken@7393
|
80 |
storage->array[id-1].data = SDL_const_cast(void*, value);
|
slouken@7393
|
81 |
storage->array[id-1].destructor = destructor;
|
slouken@7393
|
82 |
return 0;
|
slouken@7393
|
83 |
}
|
slouken@7393
|
84 |
|
slouken@7393
|
85 |
static void
|
slouken@7393
|
86 |
SDL_TLSCleanup()
|
slouken@7393
|
87 |
{
|
slouken@7393
|
88 |
SDL_TLSData *storage;
|
slouken@7393
|
89 |
|
slouken@7393
|
90 |
storage = SDL_SYS_GetTLSData();
|
slouken@7393
|
91 |
if (storage) {
|
icculus@7484
|
92 |
unsigned int i;
|
slouken@7393
|
93 |
for (i = 0; i < storage->limit; ++i) {
|
slouken@7393
|
94 |
if (storage->array[i].destructor) {
|
slouken@7393
|
95 |
storage->array[i].destructor(storage->array[i].data);
|
slouken@7393
|
96 |
}
|
slouken@7393
|
97 |
}
|
slouken@7393
|
98 |
SDL_SYS_SetTLSData(NULL);
|
slouken@7393
|
99 |
SDL_free(storage);
|
slouken@7393
|
100 |
}
|
slouken@7393
|
101 |
}
|
slouken@7393
|
102 |
|
slouken@7393
|
103 |
|
slouken@7393
|
104 |
/* This is a generic implementation of thread-local storage which doesn't
|
slouken@7393
|
105 |
require additional OS support.
|
slouken@7393
|
106 |
|
slouken@7393
|
107 |
It is not especially efficient and doesn't clean up thread-local storage
|
slouken@7393
|
108 |
as threads exit. If there is a real OS that doesn't support thread-local
|
slouken@7393
|
109 |
storage this implementation should be improved to be production quality.
|
slouken@7393
|
110 |
*/
|
slouken@7393
|
111 |
|
slouken@7393
|
112 |
typedef struct SDL_TLSEntry {
|
slouken@7393
|
113 |
SDL_threadID thread;
|
slouken@7393
|
114 |
SDL_TLSData *storage;
|
slouken@7393
|
115 |
struct SDL_TLSEntry *next;
|
slouken@7393
|
116 |
} SDL_TLSEntry;
|
slouken@7393
|
117 |
|
slouken@7393
|
118 |
static SDL_mutex *SDL_generic_TLS_mutex;
|
slouken@7393
|
119 |
static SDL_TLSEntry *SDL_generic_TLS;
|
slouken@7393
|
120 |
|
slouken@7393
|
121 |
|
slouken@7393
|
122 |
SDL_TLSData *
|
slouken@7393
|
123 |
SDL_Generic_GetTLSData()
|
slouken@7393
|
124 |
{
|
slouken@7393
|
125 |
SDL_threadID thread = SDL_ThreadID();
|
slouken@7393
|
126 |
SDL_TLSEntry *entry;
|
slouken@7393
|
127 |
SDL_TLSData *storage = NULL;
|
slouken@7393
|
128 |
|
slouken@7730
|
129 |
#if !SDL_THREADS_DISABLED
|
slouken@7393
|
130 |
if (!SDL_generic_TLS_mutex) {
|
slouken@7393
|
131 |
static SDL_SpinLock tls_lock;
|
slouken@7393
|
132 |
SDL_AtomicLock(&tls_lock);
|
slouken@7393
|
133 |
if (!SDL_generic_TLS_mutex) {
|
slouken@7393
|
134 |
SDL_mutex *mutex = SDL_CreateMutex();
|
slouken@7393
|
135 |
SDL_MemoryBarrierRelease();
|
slouken@7393
|
136 |
SDL_generic_TLS_mutex = mutex;
|
slouken@7393
|
137 |
if (!SDL_generic_TLS_mutex) {
|
slouken@7393
|
138 |
SDL_AtomicUnlock(&tls_lock);
|
slouken@7393
|
139 |
return NULL;
|
slouken@7393
|
140 |
}
|
slouken@7393
|
141 |
}
|
slouken@7393
|
142 |
SDL_AtomicUnlock(&tls_lock);
|
slouken@7393
|
143 |
}
|
slouken@7730
|
144 |
#endif /* SDL_THREADS_DISABLED */
|
slouken@7393
|
145 |
|
slouken@7393
|
146 |
SDL_MemoryBarrierAcquire();
|
slouken@7393
|
147 |
SDL_LockMutex(SDL_generic_TLS_mutex);
|
slouken@7393
|
148 |
for (entry = SDL_generic_TLS; entry; entry = entry->next) {
|
slouken@7393
|
149 |
if (entry->thread == thread) {
|
slouken@7393
|
150 |
storage = entry->storage;
|
slouken@7393
|
151 |
break;
|
slouken@7393
|
152 |
}
|
slouken@7393
|
153 |
}
|
slouken@7730
|
154 |
#if !SDL_THREADS_DISABLED
|
slouken@7393
|
155 |
SDL_UnlockMutex(SDL_generic_TLS_mutex);
|
slouken@7730
|
156 |
#endif
|
slouken@7393
|
157 |
|
slouken@7393
|
158 |
return storage;
|
slouken@7393
|
159 |
}
|
slouken@7393
|
160 |
|
slouken@7393
|
161 |
int
|
slouken@7393
|
162 |
SDL_Generic_SetTLSData(SDL_TLSData *storage)
|
slouken@7393
|
163 |
{
|
slouken@7393
|
164 |
SDL_threadID thread = SDL_ThreadID();
|
slouken@7393
|
165 |
SDL_TLSEntry *prev, *entry;
|
slouken@7393
|
166 |
|
slouken@7393
|
167 |
/* SDL_Generic_GetTLSData() is always called first, so we can assume SDL_generic_TLS_mutex */
|
slouken@7393
|
168 |
SDL_LockMutex(SDL_generic_TLS_mutex);
|
slouken@7393
|
169 |
prev = NULL;
|
slouken@7393
|
170 |
for (entry = SDL_generic_TLS; entry; entry = entry->next) {
|
slouken@7393
|
171 |
if (entry->thread == thread) {
|
slouken@7393
|
172 |
if (storage) {
|
slouken@7393
|
173 |
entry->storage = storage;
|
slouken@7393
|
174 |
} else {
|
slouken@7393
|
175 |
if (prev) {
|
slouken@7393
|
176 |
prev->next = entry->next;
|
slouken@7393
|
177 |
} else {
|
slouken@7393
|
178 |
SDL_generic_TLS = entry->next;
|
slouken@7393
|
179 |
}
|
slouken@7393
|
180 |
SDL_free(entry);
|
slouken@7393
|
181 |
}
|
slouken@7393
|
182 |
break;
|
slouken@7393
|
183 |
}
|
slouken@7393
|
184 |
prev = entry;
|
slouken@7393
|
185 |
}
|
slouken@7393
|
186 |
if (!entry) {
|
slouken@7393
|
187 |
entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
|
slouken@7393
|
188 |
if (entry) {
|
slouken@7393
|
189 |
entry->thread = thread;
|
slouken@7393
|
190 |
entry->storage = storage;
|
slouken@7393
|
191 |
entry->next = SDL_generic_TLS;
|
slouken@7393
|
192 |
SDL_generic_TLS = entry;
|
slouken@7393
|
193 |
}
|
slouken@7393
|
194 |
}
|
slouken@7393
|
195 |
SDL_UnlockMutex(SDL_generic_TLS_mutex);
|
slouken@7393
|
196 |
|
slouken@7393
|
197 |
if (!entry) {
|
slouken@7393
|
198 |
return SDL_OutOfMemory();
|
slouken@7393
|
199 |
}
|
slouken@7393
|
200 |
return 0;
|
slouken@7393
|
201 |
}
|
slouken@7393
|
202 |
|
slouken@0
|
203 |
/* Routine to get the thread-specific error variable */
|
slouken@1895
|
204 |
SDL_error *
|
slouken@1895
|
205 |
SDL_GetErrBuf(void)
|
slouken@0
|
206 |
{
|
slouken@7393
|
207 |
static SDL_SpinLock tls_lock;
|
slouken@7391
|
208 |
static SDL_bool tls_being_created;
|
slouken@7391
|
209 |
static SDL_TLSID tls_errbuf;
|
slouken@7391
|
210 |
static SDL_error SDL_global_errbuf;
|
slouken@7393
|
211 |
const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1;
|
slouken@1895
|
212 |
SDL_error *errbuf;
|
slouken@0
|
213 |
|
slouken@7393
|
214 |
/* tls_being_created is there simply to prevent recursion if SDL_TLSCreate() fails.
|
slouken@7393
|
215 |
It also means it's possible for another thread to also use SDL_global_errbuf,
|
slouken@7393
|
216 |
but that's very unlikely and hopefully won't cause issues.
|
slouken@7393
|
217 |
*/
|
slouken@7391
|
218 |
if (!tls_errbuf && !tls_being_created) {
|
slouken@7393
|
219 |
SDL_AtomicLock(&tls_lock);
|
slouken@7391
|
220 |
if (!tls_errbuf) {
|
slouken@7393
|
221 |
SDL_TLSID slot;
|
slouken@7391
|
222 |
tls_being_created = SDL_TRUE;
|
slouken@7393
|
223 |
slot = SDL_TLSCreate();
|
slouken@7391
|
224 |
tls_being_created = SDL_FALSE;
|
slouken@7393
|
225 |
SDL_MemoryBarrierRelease();
|
slouken@7393
|
226 |
tls_errbuf = slot;
|
slouken@7391
|
227 |
}
|
slouken@7393
|
228 |
SDL_AtomicUnlock(&tls_lock);
|
slouken@7391
|
229 |
}
|
slouken@7391
|
230 |
if (!tls_errbuf) {
|
slouken@7391
|
231 |
return &SDL_global_errbuf;
|
slouken@7391
|
232 |
}
|
slouken@0
|
233 |
|
slouken@7393
|
234 |
SDL_MemoryBarrierAcquire();
|
slouken@7393
|
235 |
errbuf = (SDL_error *)SDL_TLSGet(tls_errbuf);
|
slouken@7393
|
236 |
if (errbuf == ALLOCATION_IN_PROGRESS) {
|
slouken@7393
|
237 |
return &SDL_global_errbuf;
|
slouken@7393
|
238 |
}
|
slouken@7391
|
239 |
if (!errbuf) {
|
slouken@7393
|
240 |
/* Mark that we're in the middle of allocating our buffer */
|
slouken@7393
|
241 |
SDL_TLSSet(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL);
|
slouken@7391
|
242 |
errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
|
slouken@7391
|
243 |
if (!errbuf) {
|
slouken@7393
|
244 |
SDL_TLSSet(tls_errbuf, NULL, NULL);
|
slouken@7391
|
245 |
return &SDL_global_errbuf;
|
slouken@1895
|
246 |
}
|
slouken@7391
|
247 |
SDL_zerop(errbuf);
|
slouken@7393
|
248 |
SDL_TLSSet(tls_errbuf, errbuf, SDL_free);
|
slouken@1895
|
249 |
}
|
slouken@7391
|
250 |
return errbuf;
|
slouken@0
|
251 |
}
|
slouken@0
|
252 |
|
slouken@0
|
253 |
|
slouken@0
|
254 |
/* Arguments and callback to setup and run the user thread function */
|
slouken@1895
|
255 |
typedef struct
|
slouken@1895
|
256 |
{
|
slouken@1895
|
257 |
int (SDLCALL * func) (void *);
|
slouken@1895
|
258 |
void *data;
|
slouken@1895
|
259 |
SDL_Thread *info;
|
slouken@1895
|
260 |
SDL_sem *wait;
|
slouken@0
|
261 |
} thread_args;
|
slouken@0
|
262 |
|
slouken@1895
|
263 |
void
|
slouken@1895
|
264 |
SDL_RunThread(void *data)
|
slouken@0
|
265 |
{
|
icculus@5969
|
266 |
thread_args *args = (thread_args *) data;
|
icculus@5969
|
267 |
int (SDLCALL * userfunc) (void *) = args->func;
|
icculus@5969
|
268 |
void *userdata = args->data;
|
icculus@7978
|
269 |
SDL_Thread *thread = args->info;
|
icculus@7978
|
270 |
int *statusloc = &thread->status;
|
slouken@0
|
271 |
|
slouken@7393
|
272 |
/* Perform any system-dependent setup - this function may not fail */
|
icculus@7978
|
273 |
SDL_SYS_SetupThread(thread->name);
|
slouken@0
|
274 |
|
slouken@1895
|
275 |
/* Get the thread id */
|
icculus@7978
|
276 |
thread->threadid = SDL_ThreadID();
|
slouken@0
|
277 |
|
slouken@1895
|
278 |
/* Wake up the parent thread */
|
slouken@1895
|
279 |
SDL_SemPost(args->wait);
|
slouken@0
|
280 |
|
slouken@1895
|
281 |
/* Run the function */
|
slouken@1895
|
282 |
*statusloc = userfunc(userdata);
|
slouken@7393
|
283 |
|
slouken@7393
|
284 |
/* Clean up thread-local storage */
|
slouken@7393
|
285 |
SDL_TLSCleanup();
|
icculus@7978
|
286 |
|
icculus@7978
|
287 |
/* Mark us as ready to be joined (or detached) */
|
icculus@7978
|
288 |
if (!SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_ZOMBIE)) {
|
icculus@7978
|
289 |
/* Clean up if something already detached us. */
|
icculus@7978
|
290 |
if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_DETACHED, SDL_THREAD_STATE_CLEANED)) {
|
icculus@7978
|
291 |
if (thread->name) {
|
icculus@7978
|
292 |
SDL_free(thread->name);
|
icculus@7978
|
293 |
}
|
icculus@7978
|
294 |
SDL_free(thread);
|
icculus@7978
|
295 |
}
|
icculus@7978
|
296 |
}
|
slouken@0
|
297 |
}
|
slouken@0
|
298 |
|
icculus@8094
|
299 |
#ifdef SDL_CreateThread
|
icculus@8094
|
300 |
#undef SDL_CreateThread
|
icculus@8094
|
301 |
#endif
|
icculus@8094
|
302 |
#if SDL_DYNAMIC_API
|
icculus@8094
|
303 |
#define SDL_CreateThread SDL_CreateThread_REAL
|
icculus@8094
|
304 |
#endif
|
icculus@8094
|
305 |
|
slouken@1471
|
306 |
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
slouken@1895
|
307 |
DECLSPEC SDL_Thread *SDLCALL
|
icculus@5969
|
308 |
SDL_CreateThread(int (SDLCALL * fn) (void *),
|
icculus@5969
|
309 |
const char *name, void *data,
|
slouken@1895
|
310 |
pfnSDL_CurrentBeginThread pfnBeginThread,
|
slouken@1895
|
311 |
pfnSDL_CurrentEndThread pfnEndThread)
|
icculus@1190
|
312 |
#else
|
slouken@1895
|
313 |
DECLSPEC SDL_Thread *SDLCALL
|
icculus@5969
|
314 |
SDL_CreateThread(int (SDLCALL * fn) (void *),
|
icculus@5969
|
315 |
const char *name, void *data)
|
icculus@1190
|
316 |
#endif
|
slouken@0
|
317 |
{
|
slouken@1895
|
318 |
SDL_Thread *thread;
|
slouken@1895
|
319 |
thread_args *args;
|
slouken@1895
|
320 |
int ret;
|
slouken@0
|
321 |
|
slouken@1895
|
322 |
/* Allocate memory for the thread info structure */
|
slouken@1895
|
323 |
thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
|
slouken@1895
|
324 |
if (thread == NULL) {
|
slouken@1895
|
325 |
SDL_OutOfMemory();
|
slouken@1895
|
326 |
return (NULL);
|
slouken@1895
|
327 |
}
|
icculus@7978
|
328 |
SDL_zerop(thread);
|
slouken@1895
|
329 |
thread->status = -1;
|
icculus@7978
|
330 |
SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
|
slouken@0
|
331 |
|
slouken@1895
|
332 |
/* Set up the arguments for the thread */
|
icculus@5969
|
333 |
if (name != NULL) {
|
icculus@5969
|
334 |
thread->name = SDL_strdup(name);
|
icculus@5969
|
335 |
if (thread->name == NULL) {
|
icculus@5969
|
336 |
SDL_OutOfMemory();
|
icculus@5969
|
337 |
SDL_free(thread);
|
icculus@5969
|
338 |
return (NULL);
|
icculus@5969
|
339 |
}
|
icculus@5969
|
340 |
}
|
icculus@5969
|
341 |
|
icculus@5969
|
342 |
/* Set up the arguments for the thread */
|
slouken@1895
|
343 |
args = (thread_args *) SDL_malloc(sizeof(*args));
|
slouken@1895
|
344 |
if (args == NULL) {
|
slouken@1895
|
345 |
SDL_OutOfMemory();
|
slouken@7606
|
346 |
if (thread->name) {
|
slouken@7606
|
347 |
SDL_free(thread->name);
|
slouken@7606
|
348 |
}
|
slouken@1895
|
349 |
SDL_free(thread);
|
slouken@1895
|
350 |
return (NULL);
|
slouken@1895
|
351 |
}
|
slouken@1895
|
352 |
args->func = fn;
|
slouken@1895
|
353 |
args->data = data;
|
slouken@1895
|
354 |
args->info = thread;
|
slouken@1895
|
355 |
args->wait = SDL_CreateSemaphore(0);
|
slouken@1895
|
356 |
if (args->wait == NULL) {
|
slouken@7606
|
357 |
if (thread->name) {
|
slouken@7606
|
358 |
SDL_free(thread->name);
|
slouken@7606
|
359 |
}
|
slouken@1895
|
360 |
SDL_free(thread);
|
slouken@1895
|
361 |
SDL_free(args);
|
slouken@1895
|
362 |
return (NULL);
|
slouken@1895
|
363 |
}
|
slouken@0
|
364 |
|
slouken@1895
|
365 |
/* Create the thread and go! */
|
slouken@1471
|
366 |
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
slouken@1895
|
367 |
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
|
icculus@1190
|
368 |
#else
|
slouken@1895
|
369 |
ret = SDL_SYS_CreateThread(thread, args);
|
icculus@1190
|
370 |
#endif
|
slouken@1895
|
371 |
if (ret >= 0) {
|
slouken@1895
|
372 |
/* Wait for the thread function to use arguments */
|
slouken@1895
|
373 |
SDL_SemWait(args->wait);
|
slouken@1895
|
374 |
} else {
|
slouken@1895
|
375 |
/* Oops, failed. Gotta free everything */
|
slouken@7606
|
376 |
if (thread->name) {
|
slouken@7606
|
377 |
SDL_free(thread->name);
|
slouken@7606
|
378 |
}
|
slouken@1895
|
379 |
SDL_free(thread);
|
slouken@1895
|
380 |
thread = NULL;
|
slouken@1895
|
381 |
}
|
slouken@1895
|
382 |
SDL_DestroySemaphore(args->wait);
|
slouken@1895
|
383 |
SDL_free(args);
|
slouken@0
|
384 |
|
slouken@1895
|
385 |
/* Everything is running now */
|
slouken@1895
|
386 |
return (thread);
|
slouken@0
|
387 |
}
|
slouken@0
|
388 |
|
slouken@5506
|
389 |
SDL_threadID
|
slouken@5506
|
390 |
SDL_GetThreadID(SDL_Thread * thread)
|
slouken@5506
|
391 |
{
|
slouken@5506
|
392 |
SDL_threadID id;
|
slouken@5506
|
393 |
|
slouken@5506
|
394 |
if (thread) {
|
slouken@5506
|
395 |
id = thread->threadid;
|
slouken@5506
|
396 |
} else {
|
slouken@5506
|
397 |
id = SDL_ThreadID();
|
slouken@5506
|
398 |
}
|
slouken@5506
|
399 |
return id;
|
slouken@5506
|
400 |
}
|
slouken@5506
|
401 |
|
icculus@5969
|
402 |
const char *
|
icculus@5969
|
403 |
SDL_GetThreadName(SDL_Thread * thread)
|
icculus@5969
|
404 |
{
|
slouken@7606
|
405 |
if (thread) {
|
slouken@7606
|
406 |
return thread->name;
|
slouken@7606
|
407 |
} else {
|
slouken@7606
|
408 |
return NULL;
|
slouken@7606
|
409 |
}
|
icculus@5969
|
410 |
}
|
icculus@5969
|
411 |
|
slouken@5506
|
412 |
int
|
slouken@5509
|
413 |
SDL_SetThreadPriority(SDL_ThreadPriority priority)
|
slouken@5506
|
414 |
{
|
slouken@5509
|
415 |
return SDL_SYS_SetThreadPriority(priority);
|
slouken@5506
|
416 |
}
|
slouken@5506
|
417 |
|
slouken@1895
|
418 |
void
|
slouken@1895
|
419 |
SDL_WaitThread(SDL_Thread * thread, int *status)
|
slouken@0
|
420 |
{
|
slouken@1895
|
421 |
if (thread) {
|
slouken@1895
|
422 |
SDL_SYS_WaitThread(thread);
|
slouken@1895
|
423 |
if (status) {
|
slouken@1895
|
424 |
*status = thread->status;
|
slouken@1895
|
425 |
}
|
slouken@7606
|
426 |
if (thread->name) {
|
slouken@7606
|
427 |
SDL_free(thread->name);
|
slouken@7606
|
428 |
}
|
slouken@1895
|
429 |
SDL_free(thread);
|
slouken@1895
|
430 |
}
|
slouken@0
|
431 |
}
|
slouken@0
|
432 |
|
icculus@7978
|
433 |
void
|
icculus@7978
|
434 |
SDL_DetachThread(SDL_Thread * thread)
|
icculus@7978
|
435 |
{
|
icculus@7978
|
436 |
if (!thread) {
|
icculus@7978
|
437 |
return;
|
icculus@7978
|
438 |
}
|
icculus@7978
|
439 |
|
icculus@7978
|
440 |
/* Grab dibs if the state is alive+joinable. */
|
icculus@7978
|
441 |
if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_DETACHED)) {
|
icculus@7978
|
442 |
SDL_SYS_DetachThread(thread);
|
icculus@7978
|
443 |
} else {
|
icculus@7978
|
444 |
/* all other states are pretty final, see where we landed. */
|
slouken@8922
|
445 |
const int thread_state = SDL_AtomicGet(&thread->state);
|
slouken@8922
|
446 |
if ((thread_state == SDL_THREAD_STATE_DETACHED) || (thread_state == SDL_THREAD_STATE_CLEANED)) {
|
icculus@7978
|
447 |
return; /* already detached (you shouldn't call this twice!) */
|
slouken@8922
|
448 |
} else if (thread_state == SDL_THREAD_STATE_ZOMBIE) {
|
icculus@7978
|
449 |
SDL_WaitThread(thread, NULL); /* already done, clean it up. */
|
icculus@7978
|
450 |
} else {
|
icculus@7978
|
451 |
SDL_assert(0 && "Unexpected thread state");
|
icculus@7978
|
452 |
}
|
icculus@7978
|
453 |
}
|
icculus@7978
|
454 |
}
|
icculus@7978
|
455 |
|
slouken@1895
|
456 |
/* vi: set ts=4 sw=4 expandtab: */
|