src/thread/amigaos/SDL_thread.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 16 Feb 2006 10:11:48 +0000
changeset 1361 19418e4422cb
parent 1358 c71e05b4dc2e
child 1402 d910939febfa
permissions -rw-r--r--
New configure-based build system. Still work in progress, but much improved
     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     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 
    23 /* System independent thread management routines for SDL */
    24 
    25 #include "SDL_mutex.h"
    26 #include "SDL_thread.h"
    27 #include "../SDL_thread_c.h"
    28 #include "../SDL_systhread.h"
    29 
    30 #define ARRAY_CHUNKSIZE	32
    31 /* The array of threads currently active in the application
    32    (except the main thread)
    33    The manipulation of an array here is safer than using a linked list.
    34 */
    35 static int SDL_maxthreads = 0;
    36 static int SDL_numthreads = 0;
    37 static SDL_Thread **SDL_Threads = NULL;
    38 static struct SignalSemaphore thread_lock;
    39 int thread_lock_created = 0;
    40 
    41 int SDL_ThreadsInit(void)
    42 {
    43 	InitSemaphore(&thread_lock);
    44 	thread_lock_created=1;
    45 	return 0;
    46 }
    47 
    48 /* This should never be called...
    49    If this is called by SDL_Quit(), we don't know whether or not we should
    50    clean up threads here.  If any threads are still running after this call,
    51    they will no longer have access to any per-thread data.
    52  */
    53 void SDL_ThreadsQuit()
    54 {
    55 	thread_lock_created=0;
    56 }
    57 
    58 /* Routines for manipulating the thread list */
    59 static void SDL_AddThread(SDL_Thread *thread)
    60 {
    61 	SDL_Thread **threads;
    62 
    63 	/* WARNING:
    64 	   If the very first threads are created simultaneously, then
    65 	   there could be a race condition causing memory corruption.
    66 	   In practice, this isn't a problem because by definition there
    67 	   is only one thread running the first time this is called.
    68 	*/
    69 	if ( !thread_lock_created ) {
    70 		if ( SDL_ThreadsInit() < 0 ) {
    71 			return;
    72 		}
    73 	}
    74 	ObtainSemaphore(&thread_lock);
    75 
    76 	/* Expand the list of threads, if necessary */
    77 #ifdef DEBUG_THREADS
    78 	printf("Adding thread (%d already - %d max)\n",
    79 			SDL_numthreads, SDL_maxthreads);
    80 #endif
    81 	if ( SDL_numthreads == SDL_maxthreads ) {
    82 		threads=(SDL_Thread **)SDL_malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
    83 		                              (sizeof *threads));
    84 		if ( threads == NULL ) {
    85 			SDL_OutOfMemory();
    86 			goto done;
    87 		}
    88 		SDL_memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
    89 		SDL_maxthreads += ARRAY_CHUNKSIZE;
    90 		if ( SDL_Threads ) {
    91 			SDL_free(SDL_Threads);
    92 		}
    93 		SDL_Threads = threads;
    94 	}
    95 	SDL_Threads[SDL_numthreads++] = thread;
    96 done:
    97 	ReleaseSemaphore(&thread_lock);
    98 }
    99 
   100 static void SDL_DelThread(SDL_Thread *thread)
   101 {
   102 	int i;
   103 
   104 	if ( thread_lock_created ) {
   105 		ObtainSemaphore(&thread_lock);
   106 		for ( i=0; i<SDL_numthreads; ++i ) {
   107 			if ( thread == SDL_Threads[i] ) {
   108 				break;
   109 			}
   110 		}
   111 		if ( i < SDL_numthreads ) {
   112 			--SDL_numthreads;
   113 			while ( i < SDL_numthreads ) {
   114 				SDL_Threads[i] = SDL_Threads[i+1];
   115 				++i;
   116 			}
   117 #ifdef DEBUG_THREADS
   118 			printf("Deleting thread (%d left - %d max)\n",
   119 					SDL_numthreads, SDL_maxthreads);
   120 #endif
   121 		}
   122 		ReleaseSemaphore(&thread_lock);
   123 	}
   124 }
   125 
   126 /* The default (non-thread-safe) global error variable */
   127 static SDL_error SDL_global_error;
   128 
   129 /* Routine to get the thread-specific error variable */
   130 SDL_error *SDL_GetErrBuf(void)
   131 {
   132 	SDL_error *errbuf;
   133 
   134 	errbuf = &SDL_global_error;
   135 	if ( SDL_Threads ) {
   136 		int i;
   137 		Uint32 this_thread;
   138 
   139 		this_thread = SDL_ThreadID();
   140 		ObtainSemaphore(&thread_lock);
   141 		for ( i=0; i<SDL_numthreads; ++i ) {
   142 			if ( this_thread == SDL_Threads[i]->threadid ) {
   143 				errbuf = &SDL_Threads[i]->errbuf;
   144 				break;
   145 			}
   146 		}
   147 		ReleaseSemaphore(&thread_lock);
   148 	}
   149 	return(errbuf);
   150 }
   151 
   152 
   153 /* Arguments and callback to setup and run the user thread function */
   154 typedef struct {
   155 	int (*func)(void *);
   156 	void *data;
   157 	SDL_Thread *info;
   158 	struct Task *wait;
   159 } thread_args;
   160 
   161 void SDL_RunThread(void *data)
   162 {
   163 	thread_args *args;
   164 	int (*userfunc)(void *);
   165 	void *userdata;
   166 	int *statusloc;
   167 
   168 	/* Perform any system-dependent setup
   169 	   - this function cannot fail, and cannot use SDL_SetError()
   170 	 */
   171 	SDL_SYS_SetupThread();
   172 
   173 	/* Get the thread id */
   174 	args = (thread_args *)data;
   175 	args->info->threadid = SDL_ThreadID();
   176 
   177 	/* Figure out what function to run */
   178 	userfunc = args->func;
   179 	userdata = args->data;
   180 	statusloc = &args->info->status;
   181 
   182 	/* Wake up the parent thread */
   183 	Signal(args->wait,SIGBREAKF_CTRL_E);
   184 
   185 	/* Run the function */
   186 	*statusloc = userfunc(userdata);
   187 }
   188 
   189 SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
   190 {
   191 	SDL_Thread *thread;
   192 	thread_args *args;
   193 	int ret;
   194 
   195 	/* Allocate memory for the thread info structure */
   196 	thread = (SDL_Thread *)SDL_malloc(sizeof(*thread));
   197 	if ( thread == NULL ) {
   198 		SDL_OutOfMemory();
   199 		return(NULL);
   200 	}
   201 	SDL_memset(thread, 0, (sizeof *thread));
   202 	thread->status = -1;
   203 
   204 	/* Set up the arguments for the thread */
   205 	args = (thread_args *)SDL_malloc(sizeof(*args));
   206 	if ( args == NULL ) {
   207 		SDL_OutOfMemory();
   208 		SDL_free(thread);
   209 		return(NULL);
   210 	}
   211 	args->func = fn;
   212 	args->data = data;
   213 	args->info = thread;
   214 	args->wait = FindTask(NULL);
   215 	if ( args->wait == NULL ) {
   216 		SDL_free(thread);
   217 		SDL_free(args);
   218 		SDL_OutOfMemory();
   219 		return(NULL);
   220 	}
   221 
   222 	/* Add the thread to the list of available threads */
   223 	SDL_AddThread(thread);
   224 
   225 	D(bug("Starting thread...\n"));
   226 
   227 	/* Create the thread and go! */
   228 	ret = SDL_SYS_CreateThread(thread, args);
   229 	if ( ret >= 0 ) {
   230 		D(bug("Waiting for thread CTRL_E...\n"));
   231 		/* Wait for the thread function to use arguments */
   232 		Wait(SIGBREAKF_CTRL_E);
   233 		D(bug("  Arrived."));
   234 	} else {
   235 		/* Oops, failed.  Gotta free everything */
   236 		SDL_DelThread(thread);
   237 		SDL_free(thread);
   238 		thread = NULL;
   239 	}
   240 	SDL_free(args);
   241 
   242 	/* Everything is running now */
   243 	return(thread);
   244 }
   245 
   246 void SDL_WaitThread(SDL_Thread *thread, int *status)
   247 {
   248 	if ( thread ) {
   249 		SDL_SYS_WaitThread(thread);
   250 		if ( status ) {
   251 			*status = thread->status;
   252 		}
   253 		SDL_DelThread(thread);
   254 		SDL_free(thread);
   255 	}
   256 }
   257 
   258 Uint32 SDL_GetThreadID(SDL_Thread *thread)
   259 {
   260 	Uint32 id;
   261 
   262 	if ( thread ) {
   263 		id = thread->threadid;
   264 	} else {
   265 		id = SDL_ThreadID();
   266 	}
   267 	return(id);
   268 }
   269 
   270 void SDL_KillThread(SDL_Thread *thread)
   271 {
   272 	if ( thread ) {
   273 		SDL_SYS_KillThread(thread);
   274 		SDL_WaitThread(thread, NULL);
   275 	}
   276 }
   277