This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_thread.c
291 lines (253 loc) · 7.24 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
27
/* System independent thread management routines for SDL */
#include "SDL_mutex.h"
#include "SDL_thread.h"
28
29
#include "../SDL_thread_c.h"
#include "../SDL_systhread.h"
30
31
32
33
34
35
36
37
38
39
40
41
#define ARRAY_CHUNKSIZE 32
/* The array of threads currently active in the application
(except the main thread)
The manipulation of an array here is safer than using a linked list.
*/
static int SDL_maxthreads = 0;
static int SDL_numthreads = 0;
static SDL_Thread **SDL_Threads = NULL;
static struct SignalSemaphore thread_lock;
int thread_lock_created = 0;
42
int
43
SDL_ThreadsInit(void)
44
{
45
InitSemaphore(&thread_lock);
46
47
thread_lock_created = 1;
return 0;
48
49
50
51
52
53
54
}
/* This should never be called...
If this is called by SDL_Quit(), we don't know whether or not we should
clean up threads here. If any threads are still running after this call,
they will no longer have access to any per-thread data.
*/
55
void
56
SDL_ThreadsQuit()
57
{
58
thread_lock_created = 0;
59
60
61
}
/* Routines for manipulating the thread list */
62
static void
63
SDL_AddThread(SDL_Thread * thread)
64
{
65
66
67
68
69
70
71
72
73
SDL_Thread **threads;
/* WARNING:
If the very first threads are created simultaneously, then
there could be a race condition causing memory corruption.
In practice, this isn't a problem because by definition there
is only one thread running the first time this is called.
*/
if (!thread_lock_created) {
74
if (SDL_ThreadsInit() < 0) {
75
76
77
return;
}
}
78
ObtainSemaphore(&thread_lock);
79
80
/* Expand the list of threads, if necessary */
81
#ifdef DEBUG_THREADS
82
83
printf("Adding thread (%d already - %d max)\n",
SDL_numthreads, SDL_maxthreads);
84
#endif
85
86
if (SDL_numthreads == SDL_maxthreads) {
threads =
87
88
(SDL_Thread **) SDL_malloc((SDL_maxthreads + ARRAY_CHUNKSIZE) *
(sizeof *threads));
89
if (threads == NULL) {
90
SDL_OutOfMemory();
91
92
goto done;
}
93
SDL_memcpy(threads, SDL_Threads, SDL_numthreads * (sizeof *threads));
94
95
SDL_maxthreads += ARRAY_CHUNKSIZE;
if (SDL_Threads) {
96
SDL_free(SDL_Threads);
97
98
99
100
101
}
SDL_Threads = threads;
}
SDL_Threads[SDL_numthreads++] = thread;
done:
102
ReleaseSemaphore(&thread_lock);
103
104
}
105
static void
106
SDL_DelThread(SDL_Thread * thread)
107
{
108
109
110
int i;
if (thread_lock_created) {
111
ObtainSemaphore(&thread_lock);
112
113
114
115
116
117
118
119
120
121
122
for (i = 0; i < SDL_numthreads; ++i) {
if (thread == SDL_Threads[i]) {
break;
}
}
if (i < SDL_numthreads) {
--SDL_numthreads;
while (i < SDL_numthreads) {
SDL_Threads[i] = SDL_Threads[i + 1];
++i;
}
123
#ifdef DEBUG_THREADS
124
125
printf("Deleting thread (%d left - %d max)\n",
SDL_numthreads, SDL_maxthreads);
126
#endif
127
}
128
ReleaseSemaphore(&thread_lock);
129
}
130
131
132
133
134
135
}
/* The default (non-thread-safe) global error variable */
static SDL_error SDL_global_error;
/* Routine to get the thread-specific error variable */
136
SDL_error *
137
SDL_GetErrBuf(void)
138
{
139
140
141
142
143
144
145
SDL_error *errbuf;
errbuf = &SDL_global_error;
if (SDL_Threads) {
int i;
Uint32 this_thread;
146
147
this_thread = SDL_ThreadID();
ObtainSemaphore(&thread_lock);
148
149
150
151
152
153
for (i = 0; i < SDL_numthreads; ++i) {
if (this_thread == SDL_Threads[i]->threadid) {
errbuf = &SDL_Threads[i]->errbuf;
break;
}
}
154
ReleaseSemaphore(&thread_lock);
155
156
}
return (errbuf);
157
158
159
160
}
/* Arguments and callback to setup and run the user thread function */
161
162
163
164
165
166
typedef struct
{
int (*func) (void *);
void *data;
SDL_Thread *info;
struct Task *wait;
167
168
} thread_args;
169
void
170
SDL_RunThread(void *data)
171
{
172
173
174
175
176
177
178
179
thread_args *args;
int (*userfunc) (void *);
void *userdata;
int *statusloc;
/* Perform any system-dependent setup
- this function cannot fail, and cannot use SDL_SetError()
*/
180
SDL_SYS_SetupThread();
181
182
183
/* Get the thread id */
args = (thread_args *) data;
184
args->info->threadid = SDL_ThreadID();
185
186
187
188
189
190
191
/* Figure out what function to run */
userfunc = args->func;
userdata = args->data;
statusloc = &args->info->status;
/* Wake up the parent thread */
192
Signal(args->wait, SIGBREAKF_CTRL_E);
193
194
/* Run the function */
195
*statusloc = userfunc(userdata);
196
197
}
198
SDL_Thread *
199
SDL_CreateThread(int (*fn) (void *), void *data)
200
{
201
202
203
204
205
SDL_Thread *thread;
thread_args *args;
int ret;
/* Allocate memory for the thread info structure */
206
thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
207
if (thread == NULL) {
208
SDL_OutOfMemory();
209
210
return (NULL);
}
211
SDL_memset(thread, 0, (sizeof *thread));
212
213
214
thread->status = -1;
/* Set up the arguments for the thread */
215
args = (thread_args *) SDL_malloc(sizeof(*args));
216
if (args == NULL) {
217
218
SDL_OutOfMemory();
SDL_free(thread);
219
220
221
222
223
return (NULL);
}
args->func = fn;
args->data = data;
args->info = thread;
224
args->wait = FindTask(NULL);
225
if (args->wait == NULL) {
226
227
228
SDL_free(thread);
SDL_free(args);
SDL_OutOfMemory();
229
230
231
232
return (NULL);
}
/* Add the thread to the list of available threads */
233
SDL_AddThread(thread);
234
235
D(bug("Starting thread...\n"));
236
237
/* Create the thread and go! */
238
ret = SDL_SYS_CreateThread(thread, args);
239
if (ret >= 0) {
240
D(bug("Waiting for thread CTRL_E...\n"));
241
/* Wait for the thread function to use arguments */
242
243
Wait(SIGBREAKF_CTRL_E);
D(bug(" Arrived."));
244
245
} else {
/* Oops, failed. Gotta free everything */
246
247
SDL_DelThread(thread);
SDL_free(thread);
248
249
thread = NULL;
}
250
SDL_free(args);
251
252
253
/* Everything is running now */
return (thread);
254
255
}
256
void
257
SDL_WaitThread(SDL_Thread * thread, int *status)
258
{
259
if (thread) {
260
SDL_SYS_WaitThread(thread);
261
262
263
if (status) {
*status = thread->status;
}
264
265
SDL_DelThread(thread);
SDL_free(thread);
266
}
267
268
}
269
Uint32
270
SDL_GetThreadID(SDL_Thread * thread)
271
{
272
273
274
275
276
Uint32 id;
if (thread) {
id = thread->threadid;
} else {
277
id = SDL_ThreadID();
278
279
}
return (id);
280
281
}
282
void
283
SDL_KillThread(SDL_Thread * thread)
284
{
285
if (thread) {
286
287
SDL_SYS_KillThread(thread);
SDL_WaitThread(thread, NULL);
288
}
289
290
}
291
/* vi: set ts=4 sw=4 expandtab: */