diff options
Diffstat (limited to 'apps/plugins/sdl/src/thread/SDL_thread.c')
-rw-r--r-- | apps/plugins/sdl/src/thread/SDL_thread.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/thread/SDL_thread.c b/apps/plugins/sdl/src/thread/SDL_thread.c new file mode 100644 index 0000000000..250371dd89 --- /dev/null +++ b/apps/plugins/sdl/src/thread/SDL_thread.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 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 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | 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 | /* System independent thread management routines for SDL */ | ||
25 | |||
26 | #include "SDL_mutex.h" | ||
27 | #include "SDL_thread.h" | ||
28 | #include "SDL_thread_c.h" | ||
29 | #include "SDL_systhread.h" | ||
30 | |||
31 | #define ARRAY_CHUNKSIZE 32 | ||
32 | /* The array of threads currently active in the application | ||
33 | (except the main thread) | ||
34 | The manipulation of an array here is safer than using a linked list. | ||
35 | */ | ||
36 | static int SDL_maxthreads = 0; | ||
37 | static int SDL_numthreads = 0; | ||
38 | static SDL_Thread **SDL_Threads = NULL; | ||
39 | static SDL_mutex *thread_lock = NULL; | ||
40 | |||
41 | int SDL_ThreadsInit(void) | ||
42 | { | ||
43 | int retval; | ||
44 | |||
45 | retval = 0; | ||
46 | thread_lock = SDL_CreateMutex(); | ||
47 | if ( thread_lock == NULL ) { | ||
48 | retval = -1; | ||
49 | } | ||
50 | return(retval); | ||
51 | } | ||
52 | |||
53 | /* This should never be called... | ||
54 | If this is called by SDL_Quit(), we don't know whether or not we should | ||
55 | clean up threads here. If any threads are still running after this call, | ||
56 | they will no longer have access to any per-thread data. | ||
57 | */ | ||
58 | void SDL_ThreadsQuit(void) | ||
59 | { | ||
60 | SDL_mutex *mutex; | ||
61 | |||
62 | mutex = thread_lock; | ||
63 | thread_lock = NULL; | ||
64 | if ( mutex != NULL ) { | ||
65 | SDL_DestroyMutex(mutex); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /* Routines for manipulating the thread list */ | ||
70 | static void SDL_AddThread(SDL_Thread *thread) | ||
71 | { | ||
72 | /* WARNING: | ||
73 | If the very first threads are created simultaneously, then | ||
74 | there could be a race condition causing memory corruption. | ||
75 | In practice, this isn't a problem because by definition there | ||
76 | is only one thread running the first time this is called. | ||
77 | */ | ||
78 | if ( !thread_lock ) { | ||
79 | if ( SDL_ThreadsInit() < 0 ) { | ||
80 | return; | ||
81 | } | ||
82 | } | ||
83 | SDL_mutexP(thread_lock); | ||
84 | |||
85 | /* Expand the list of threads, if necessary */ | ||
86 | #ifdef DEBUG_THREADS | ||
87 | printf("Adding thread (%d already - %d max)\n", | ||
88 | SDL_numthreads, SDL_maxthreads); | ||
89 | #endif | ||
90 | if ( SDL_numthreads == SDL_maxthreads ) { | ||
91 | SDL_Thread **threads; | ||
92 | threads = (SDL_Thread **)SDL_realloc(SDL_Threads, | ||
93 | (SDL_maxthreads+ARRAY_CHUNKSIZE)*(sizeof *threads)); | ||
94 | if ( threads == NULL ) { | ||
95 | SDL_OutOfMemory(); | ||
96 | goto done; | ||
97 | } | ||
98 | SDL_maxthreads += ARRAY_CHUNKSIZE; | ||
99 | SDL_Threads = threads; | ||
100 | } | ||
101 | SDL_Threads[SDL_numthreads++] = thread; | ||
102 | done: | ||
103 | SDL_mutexV(thread_lock); | ||
104 | } | ||
105 | |||
106 | static void SDL_DelThread(SDL_Thread *thread) | ||
107 | { | ||
108 | int i; | ||
109 | |||
110 | if ( !thread_lock ) { | ||
111 | return; | ||
112 | } | ||
113 | SDL_mutexP(thread_lock); | ||
114 | for ( i=0; i<SDL_numthreads; ++i ) { | ||
115 | if ( thread == SDL_Threads[i] ) { | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | if ( i < SDL_numthreads ) { | ||
120 | if ( --SDL_numthreads > 0 ) { | ||
121 | while ( i < SDL_numthreads ) { | ||
122 | SDL_Threads[i] = SDL_Threads[i+1]; | ||
123 | ++i; | ||
124 | } | ||
125 | } else { | ||
126 | SDL_maxthreads = 0; | ||
127 | SDL_free(SDL_Threads); | ||
128 | SDL_Threads = NULL; | ||
129 | } | ||
130 | #ifdef DEBUG_THREADS | ||
131 | printf("Deleting thread (%d left - %d max)\n", | ||
132 | SDL_numthreads, SDL_maxthreads); | ||
133 | #endif | ||
134 | } | ||
135 | SDL_mutexV(thread_lock); | ||
136 | |||
137 | #if 0 /* There could be memory corruption if another thread is starting */ | ||
138 | if ( SDL_Threads == NULL ) { | ||
139 | SDL_ThreadsQuit(); | ||
140 | } | ||
141 | #endif | ||
142 | } | ||
143 | |||
144 | /* The default (non-thread-safe) global error variable */ | ||
145 | static SDL_error SDL_global_error; | ||
146 | |||
147 | /* Routine to get the thread-specific error variable */ | ||
148 | SDL_error *SDL_GetErrBuf(void) | ||
149 | { | ||
150 | SDL_error *errbuf; | ||
151 | |||
152 | errbuf = &SDL_global_error; | ||
153 | if ( SDL_Threads ) { | ||
154 | int i; | ||
155 | Uint32 this_thread; | ||
156 | |||
157 | this_thread = SDL_ThreadID(); | ||
158 | SDL_mutexP(thread_lock); | ||
159 | for ( i=0; i<SDL_numthreads; ++i ) { | ||
160 | if ( this_thread == SDL_Threads[i]->threadid ) { | ||
161 | errbuf = &SDL_Threads[i]->errbuf; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | SDL_mutexV(thread_lock); | ||
166 | } | ||
167 | return(errbuf); | ||
168 | } | ||
169 | |||
170 | |||
171 | /* Arguments and callback to setup and run the user thread function */ | ||
172 | typedef struct { | ||
173 | int (SDLCALL *func)(void *); | ||
174 | void *data; | ||
175 | SDL_Thread *info; | ||
176 | SDL_sem *wait; | ||
177 | } thread_args; | ||
178 | |||
179 | void SDL_RunThread(void *data) | ||
180 | { | ||
181 | thread_args *args; | ||
182 | int (SDLCALL *userfunc)(void *); | ||
183 | void *userdata; | ||
184 | int *statusloc; | ||
185 | |||
186 | /* Perform any system-dependent setup | ||
187 | - this function cannot fail, and cannot use SDL_SetError() | ||
188 | */ | ||
189 | SDL_SYS_SetupThread(); | ||
190 | |||
191 | /* Get the thread id */ | ||
192 | args = (thread_args *)data; | ||
193 | args->info->threadid = SDL_ThreadID(); | ||
194 | |||
195 | /* Figure out what function to run */ | ||
196 | userfunc = args->func; | ||
197 | userdata = args->data; | ||
198 | statusloc = &args->info->status; | ||
199 | |||
200 | /* Wake up the parent thread */ | ||
201 | SDL_SemPost(args->wait); | ||
202 | |||
203 | /* Run the function */ | ||
204 | *statusloc = userfunc(userdata); | ||
205 | } | ||
206 | |||
207 | #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD | ||
208 | #undef SDL_CreateThread | ||
209 | DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (SDLCALL *fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) | ||
210 | #else | ||
211 | DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (SDLCALL *fn)(void *), void *data) | ||
212 | #endif | ||
213 | { | ||
214 | SDL_Thread *thread; | ||
215 | thread_args *args; | ||
216 | int ret; | ||
217 | |||
218 | /* Allocate memory for the thread info structure */ | ||
219 | thread = (SDL_Thread *)SDL_malloc(sizeof(*thread)); | ||
220 | if ( thread == NULL ) { | ||
221 | SDL_OutOfMemory(); | ||
222 | return(NULL); | ||
223 | } | ||
224 | SDL_memset(thread, 0, (sizeof *thread)); | ||
225 | thread->status = -1; | ||
226 | |||
227 | /* Set up the arguments for the thread */ | ||
228 | args = (thread_args *)SDL_malloc(sizeof(*args)); | ||
229 | if ( args == NULL ) { | ||
230 | SDL_OutOfMemory(); | ||
231 | SDL_free(thread); | ||
232 | return(NULL); | ||
233 | } | ||
234 | args->func = fn; | ||
235 | args->data = data; | ||
236 | args->info = thread; | ||
237 | args->wait = SDL_CreateSemaphore(0); | ||
238 | if ( args->wait == NULL ) { | ||
239 | SDL_free(thread); | ||
240 | SDL_free(args); | ||
241 | return(NULL); | ||
242 | } | ||
243 | |||
244 | /* Add the thread to the list of available threads */ | ||
245 | SDL_AddThread(thread); | ||
246 | |||
247 | /* Create the thread and go! */ | ||
248 | #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD | ||
249 | ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread); | ||
250 | #else | ||
251 | ret = SDL_SYS_CreateThread(thread, args); | ||
252 | #endif | ||
253 | if ( ret >= 0 ) { | ||
254 | /* Wait for the thread function to use arguments */ | ||
255 | SDL_SemWait(args->wait); | ||
256 | } else { | ||
257 | /* Oops, failed. Gotta free everything */ | ||
258 | SDL_DelThread(thread); | ||
259 | SDL_free(thread); | ||
260 | thread = NULL; | ||
261 | } | ||
262 | SDL_DestroySemaphore(args->wait); | ||
263 | SDL_free(args); | ||
264 | |||
265 | /* Everything is running now */ | ||
266 | return(thread); | ||
267 | } | ||
268 | |||
269 | void SDL_WaitThread(SDL_Thread *thread, int *status) | ||
270 | { | ||
271 | if ( thread ) { | ||
272 | SDL_SYS_WaitThread(thread); | ||
273 | if ( status ) { | ||
274 | *status = thread->status; | ||
275 | } | ||
276 | SDL_DelThread(thread); | ||
277 | SDL_free(thread); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | Uint32 SDL_GetThreadID(SDL_Thread *thread) | ||
282 | { | ||
283 | Uint32 id; | ||
284 | |||
285 | if ( thread ) { | ||
286 | id = thread->threadid; | ||
287 | } else { | ||
288 | id = SDL_ThreadID(); | ||
289 | } | ||
290 | return(id); | ||
291 | } | ||
292 | |||
293 | void SDL_KillThread(SDL_Thread *thread) | ||
294 | { | ||
295 | if ( thread ) { | ||
296 | SDL_SYS_KillThread(thread); | ||
297 | SDL_WaitThread(thread, NULL); | ||
298 | } | ||
299 | } | ||
300 | |||