comparison src/thread/amigaos/SDL_thread.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children 75a95f82bc1f
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@devolution.com
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* System independent thread management routines for SDL */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "SDL_error.h"
35 #include "SDL_mutex.h"
36 #include "SDL_thread.h"
37 #include "SDL_thread_c.h"
38 #include "SDL_systhread.h"
39
40 #define ARRAY_CHUNKSIZE 32
41 /* The array of threads currently active in the application
42 (except the main thread)
43 The manipulation of an array here is safer than using a linked list.
44 */
45 static int SDL_maxthreads = 0;
46 static int SDL_numthreads = 0;
47 static SDL_Thread **SDL_Threads = NULL;
48 static struct SignalSemaphore thread_lock;
49 int thread_lock_created = 0;
50
51 int SDL_ThreadsInit(void)
52 {
53 InitSemaphore(&thread_lock);
54 thread_lock_created=1;
55 return 0;
56 }
57
58 /* This should never be called...
59 If this is called by SDL_Quit(), we don't know whether or not we should
60 clean up threads here. If any threads are still running after this call,
61 they will no longer have access to any per-thread data.
62 */
63 void SDL_ThreadsQuit()
64 {
65 thread_lock_created=0;
66 }
67
68 /* Routines for manipulating the thread list */
69 static void SDL_AddThread(SDL_Thread *thread)
70 {
71 SDL_Thread **threads;
72
73 /* WARNING:
74 If the very first threads are created simultaneously, then
75 there could be a race condition causing memory corruption.
76 In practice, this isn't a problem because by definition there
77 is only one thread running the first time this is called.
78 */
79 if ( !thread_lock_created ) {
80 if ( SDL_ThreadsInit() < 0 ) {
81 return;
82 }
83 }
84 ObtainSemaphore(&thread_lock);
85
86 /* Expand the list of threads, if necessary */
87 #ifdef DEBUG_THREADS
88 printf("Adding thread (%d already - %d max)\n",
89 SDL_numthreads, SDL_maxthreads);
90 #endif
91 if ( SDL_numthreads == SDL_maxthreads ) {
92 threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
93 (sizeof *threads));
94 if ( threads == NULL ) {
95 SDL_OutOfMemory();
96 goto done;
97 }
98 memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
99 SDL_maxthreads += ARRAY_CHUNKSIZE;
100 if ( SDL_Threads ) {
101 free(SDL_Threads);
102 }
103 SDL_Threads = threads;
104 }
105 SDL_Threads[SDL_numthreads++] = thread;
106 done:
107 ReleaseSemaphore(&thread_lock);
108 }
109
110 static void SDL_DelThread(SDL_Thread *thread)
111 {
112 int i;
113
114 if ( thread_lock_created ) {
115 ObtainSemaphore(&thread_lock);
116 for ( i=0; i<SDL_numthreads; ++i ) {
117 if ( thread == SDL_Threads[i] ) {
118 break;
119 }
120 }
121 if ( i < SDL_numthreads ) {
122 --SDL_numthreads;
123 while ( i < SDL_numthreads ) {
124 SDL_Threads[i] = SDL_Threads[i+1];
125 ++i;
126 }
127 #ifdef DEBUG_THREADS
128 printf("Deleting thread (%d left - %d max)\n",
129 SDL_numthreads, SDL_maxthreads);
130 #endif
131 }
132 ReleaseSemaphore(&thread_lock);
133 }
134 }
135
136 /* The default (non-thread-safe) global error variable */
137 static SDL_error SDL_global_error;
138
139 /* Routine to get the thread-specific error variable */
140 SDL_error *SDL_GetErrBuf(void)
141 {
142 SDL_error *errbuf;
143
144 errbuf = &SDL_global_error;
145 if ( SDL_Threads ) {
146 int i;
147 Uint32 this_thread;
148
149 this_thread = SDL_ThreadID();
150 ObtainSemaphore(&thread_lock);
151 for ( i=0; i<SDL_numthreads; ++i ) {
152 if ( this_thread == SDL_Threads[i]->threadid ) {
153 errbuf = &SDL_Threads[i]->errbuf;
154 break;
155 }
156 }
157 ReleaseSemaphore(&thread_lock);
158 }
159 return(errbuf);
160 }
161
162
163 /* Arguments and callback to setup and run the user thread function */
164 typedef struct {
165 int (*func)(void *);
166 void *data;
167 SDL_Thread *info;
168 struct Task *wait;
169 } thread_args;
170
171 void SDL_RunThread(void *data)
172 {
173 thread_args *args;
174 int (*userfunc)(void *);
175 void *userdata;
176 int *statusloc;
177
178 /* Perform any system-dependent setup
179 - this function cannot fail, and cannot use SDL_SetError()
180 */
181 SDL_SYS_SetupThread();
182
183 /* Get the thread id */
184 args = (thread_args *)data;
185 args->info->threadid = SDL_ThreadID();
186
187 /* Figure out what function to run */
188 userfunc = args->func;
189 userdata = args->data;
190 statusloc = &args->info->status;
191
192 /* Wake up the parent thread */
193 Signal(args->wait,SIGBREAKF_CTRL_E);
194
195 /* Run the function */
196 *statusloc = userfunc(userdata);
197 }
198
199 SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
200 {
201 SDL_Thread *thread;
202 thread_args *args;
203 int ret;
204
205 /* Allocate memory for the thread info structure */
206 thread = (SDL_Thread *)malloc(sizeof(*thread));
207 if ( thread == NULL ) {
208 SDL_OutOfMemory();
209 return(NULL);
210 }
211 memset(thread, 0, (sizeof *thread));
212 thread->status = -1;
213
214 /* Set up the arguments for the thread */
215 args = (thread_args *)malloc(sizeof(*args));
216 if ( args == NULL ) {
217 SDL_OutOfMemory();
218 free(thread);
219 return(NULL);
220 }
221 args->func = fn;
222 args->data = data;
223 args->info = thread;
224 args->wait = FindTask(NULL);
225 if ( args->wait == NULL ) {
226 free(thread);
227 free(args);
228 SDL_OutOfMemory();
229 return(NULL);
230 }
231
232 /* 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 Wait(SIGBREAKF_CTRL_E);
243 D(bug(" Arrived."));
244 } else {
245 /* Oops, failed. Gotta free everything */
246 SDL_DelThread(thread);
247 free(thread);
248 thread = NULL;
249 }
250 free(args);
251
252 /* Everything is running now */
253 return(thread);
254 }
255
256 void SDL_WaitThread(SDL_Thread *thread, int *status)
257 {
258 if ( thread ) {
259 SDL_SYS_WaitThread(thread);
260 if ( status ) {
261 *status = thread->status;
262 }
263 SDL_DelThread(thread);
264 free(thread);
265 }
266 }
267
268 void SDL_KillThread(SDL_Thread *thread)
269 {
270 if ( thread ) {
271 SDL_SYS_KillThread(thread);
272 SDL_WaitThread(thread, NULL);
273 }
274 }
275