src/thread/SDL_thread.c
changeset 0 74212992fb08
child 252 e8157fcb3114
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/thread/SDL_thread.c	Thu Apr 26 16:45:43 2001 +0000
     1.3 @@ -0,0 +1,300 @@
     1.4 +/*
     1.5 +    SDL - Simple DirectMedia Layer
     1.6 +    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    Sam Lantinga
    1.23 +    slouken@devolution.com
    1.24 +*/
    1.25 +
    1.26 +#ifdef SAVE_RCSID
    1.27 +static char rcsid =
    1.28 + "@(#) $Id$";
    1.29 +#endif
    1.30 +
    1.31 +/* System independent thread management routines for SDL */
    1.32 +
    1.33 +#include <stdio.h>
    1.34 +#include <stdlib.h>
    1.35 +#include <string.h>
    1.36 +
    1.37 +#include "SDL_error.h"
    1.38 +#include "SDL_mutex.h"
    1.39 +#include "SDL_thread.h"
    1.40 +#include "SDL_thread_c.h"
    1.41 +#include "SDL_systhread.h"
    1.42 +
    1.43 +#define ARRAY_CHUNKSIZE	32
    1.44 +/* The array of threads currently active in the application
    1.45 +   (except the main thread)
    1.46 +   The manipulation of an array here is safer than using a linked list.
    1.47 +*/
    1.48 +static int SDL_maxthreads = 0;
    1.49 +static int SDL_numthreads = 0;
    1.50 +static SDL_Thread **SDL_Threads = NULL;
    1.51 +static SDL_mutex *thread_lock = NULL;
    1.52 +int _creating_thread_lock = 0;
    1.53 +
    1.54 +int SDL_ThreadsInit(void)
    1.55 +{
    1.56 +	int retval;
    1.57 +
    1.58 +	retval = 0;
    1.59 +	/* Set the thread lock creation flag so that we can reuse an
    1.60 +	   existing lock on the system - since this mutex never gets
    1.61 +	   destroyed (see SDL_ThreadsQuit()), we want to reuse it.
    1.62 +	*/
    1.63 +	_creating_thread_lock = 1;
    1.64 +	thread_lock = SDL_CreateMutex();
    1.65 +	_creating_thread_lock = 0;
    1.66 +	if ( thread_lock == NULL ) {
    1.67 +		retval = -1;
    1.68 +	}
    1.69 +	return(retval);
    1.70 +}
    1.71 +
    1.72 +/* This should never be called...
    1.73 +   If this is called by SDL_Quit(), we don't know whether or not we should
    1.74 +   clean up threads here.  If any threads are still running after this call,
    1.75 +   they will no longer have access to any per-thread data.
    1.76 + */
    1.77 +void SDL_ThreadsQuit()
    1.78 +{
    1.79 +	SDL_mutex *mutex;
    1.80 +
    1.81 +	mutex = thread_lock;
    1.82 +	thread_lock = NULL;
    1.83 +	if ( mutex != NULL ) {
    1.84 +		SDL_DestroyMutex(mutex);
    1.85 +	}
    1.86 +}
    1.87 +
    1.88 +/* Routines for manipulating the thread list */
    1.89 +static void SDL_AddThread(SDL_Thread *thread)
    1.90 +{
    1.91 +	SDL_Thread **threads;
    1.92 +
    1.93 +	/* WARNING:
    1.94 +	   If the very first threads are created simultaneously, then
    1.95 +	   there could be a race condition causing memory corruption.
    1.96 +	   In practice, this isn't a problem because by definition there
    1.97 +	   is only one thread running the first time this is called.
    1.98 +	*/
    1.99 +	if ( thread_lock == NULL ) {
   1.100 +		if ( SDL_ThreadsInit() < 0 ) {
   1.101 +			return;
   1.102 +		}
   1.103 +	}
   1.104 +	SDL_mutexP(thread_lock);
   1.105 +
   1.106 +	/* Expand the list of threads, if necessary */
   1.107 +#ifdef DEBUG_THREADS
   1.108 +	printf("Adding thread (%d already - %d max)\n",
   1.109 +			SDL_numthreads, SDL_maxthreads);
   1.110 +#endif
   1.111 +	if ( SDL_numthreads == SDL_maxthreads ) {
   1.112 +		threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
   1.113 +		                              (sizeof *threads));
   1.114 +		if ( threads == NULL ) {
   1.115 +			SDL_OutOfMemory();
   1.116 +			goto done;
   1.117 +		}
   1.118 +		memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
   1.119 +		SDL_maxthreads += ARRAY_CHUNKSIZE;
   1.120 +		if ( SDL_Threads ) {
   1.121 +			free(SDL_Threads);
   1.122 +		}
   1.123 +		SDL_Threads = threads;
   1.124 +	}
   1.125 +	SDL_Threads[SDL_numthreads++] = thread;
   1.126 +done:
   1.127 +	SDL_mutexV(thread_lock);
   1.128 +}
   1.129 +
   1.130 +static void SDL_DelThread(SDL_Thread *thread)
   1.131 +{
   1.132 +	int i;
   1.133 +
   1.134 +	if ( thread_lock ) {
   1.135 +		SDL_mutexP(thread_lock);
   1.136 +		for ( i=0; i<SDL_numthreads; ++i ) {
   1.137 +			if ( thread == SDL_Threads[i] ) {
   1.138 +				break;
   1.139 +			}
   1.140 +		}
   1.141 +		if ( i < SDL_numthreads ) {
   1.142 +			--SDL_numthreads;
   1.143 +			while ( i < SDL_numthreads ) {
   1.144 +				SDL_Threads[i] = SDL_Threads[i+1];
   1.145 +				++i;
   1.146 +			}
   1.147 +#ifdef DEBUG_THREADS
   1.148 +			printf("Deleting thread (%d left - %d max)\n",
   1.149 +					SDL_numthreads, SDL_maxthreads);
   1.150 +#endif
   1.151 +		}
   1.152 +		SDL_mutexV(thread_lock);
   1.153 +	}
   1.154 +}
   1.155 +
   1.156 +/* The default (non-thread-safe) global error variable */
   1.157 +static SDL_error SDL_global_error;
   1.158 +
   1.159 +/* Routine to get the thread-specific error variable */
   1.160 +SDL_error *SDL_GetErrBuf(void)
   1.161 +{
   1.162 +	SDL_error *errbuf;
   1.163 +
   1.164 +	errbuf = &SDL_global_error;
   1.165 +	if ( SDL_Threads ) {
   1.166 +		int i;
   1.167 +		Uint32 this_thread;
   1.168 +
   1.169 +		this_thread = SDL_ThreadID();
   1.170 +		SDL_mutexP(thread_lock);
   1.171 +		for ( i=0; i<SDL_numthreads; ++i ) {
   1.172 +			if ( this_thread == SDL_Threads[i]->threadid ) {
   1.173 +				errbuf = &SDL_Threads[i]->errbuf;
   1.174 +				break;
   1.175 +			}
   1.176 +		}
   1.177 +		SDL_mutexV(thread_lock);
   1.178 +	}
   1.179 +	return(errbuf);
   1.180 +}
   1.181 +
   1.182 +
   1.183 +/* Arguments and callback to setup and run the user thread function */
   1.184 +typedef struct {
   1.185 +	int (*func)(void *);
   1.186 +	void *data;
   1.187 +	SDL_Thread *info;
   1.188 +	SDL_sem *wait;
   1.189 +} thread_args;
   1.190 +
   1.191 +void SDL_RunThread(void *data)
   1.192 +{
   1.193 +	thread_args *args;
   1.194 +	int (*userfunc)(void *);
   1.195 +	void *userdata;
   1.196 +	int *statusloc;
   1.197 +
   1.198 +	/* Perform any system-dependent setup
   1.199 +	   - this function cannot fail, and cannot use SDL_SetError()
   1.200 +	 */
   1.201 +	SDL_SYS_SetupThread();
   1.202 +
   1.203 +	/* Get the thread id */
   1.204 +	args = (thread_args *)data;
   1.205 +	args->info->threadid = SDL_ThreadID();
   1.206 +
   1.207 +	/* Figure out what function to run */
   1.208 +	userfunc = args->func;
   1.209 +	userdata = args->data;
   1.210 +	statusloc = &args->info->status;
   1.211 +
   1.212 +	/* Wake up the parent thread */
   1.213 +	SDL_SemPost(args->wait);
   1.214 +
   1.215 +	/* Run the function */
   1.216 +	*statusloc = userfunc(userdata);
   1.217 +}
   1.218 +
   1.219 +SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
   1.220 +{
   1.221 +	SDL_Thread *thread;
   1.222 +	thread_args *args;
   1.223 +	int ret;
   1.224 +
   1.225 +	/* Allocate memory for the thread info structure */
   1.226 +	thread = (SDL_Thread *)malloc(sizeof(*thread));
   1.227 +	if ( thread == NULL ) {
   1.228 +		SDL_OutOfMemory();
   1.229 +		return(NULL);
   1.230 +	}
   1.231 +	memset(thread, 0, (sizeof *thread));
   1.232 +	thread->status = -1;
   1.233 +
   1.234 +	/* Set up the arguments for the thread */
   1.235 +	args = (thread_args *)malloc(sizeof(*args));
   1.236 +	if ( args == NULL ) {
   1.237 +		SDL_OutOfMemory();
   1.238 +		free(thread);
   1.239 +		return(NULL);
   1.240 +	}
   1.241 +	args->func = fn;
   1.242 +	args->data = data;
   1.243 +	args->info = thread;
   1.244 +	args->wait = SDL_CreateSemaphore(0);
   1.245 +	if ( args->wait == NULL ) {
   1.246 +		free(thread);
   1.247 +		free(args);
   1.248 +		return(NULL);
   1.249 +	}
   1.250 +
   1.251 +	/* Add the thread to the list of available threads */
   1.252 +	SDL_AddThread(thread);
   1.253 +
   1.254 +	/* Create the thread and go! */
   1.255 +	ret = SDL_SYS_CreateThread(thread, args);
   1.256 +	if ( ret >= 0 ) {
   1.257 +		/* Wait for the thread function to use arguments */
   1.258 +		SDL_SemWait(args->wait);
   1.259 +	} else {
   1.260 +		/* Oops, failed.  Gotta free everything */
   1.261 +		SDL_DelThread(thread);
   1.262 +		free(thread);
   1.263 +		thread = NULL;
   1.264 +	}
   1.265 +	SDL_DestroySemaphore(args->wait);
   1.266 +	free(args);
   1.267 +
   1.268 +	/* Everything is running now */
   1.269 +	return(thread);
   1.270 +}
   1.271 +
   1.272 +void SDL_WaitThread(SDL_Thread *thread, int *status)
   1.273 +{
   1.274 +	if ( thread ) {
   1.275 +		SDL_SYS_WaitThread(thread);
   1.276 +		if ( status ) {
   1.277 +			*status = thread->status;
   1.278 +		}
   1.279 +		SDL_DelThread(thread);
   1.280 +		free(thread);
   1.281 +	}
   1.282 +}
   1.283 +
   1.284 +Uint32 SDL_GetThreadID(SDL_Thread *thread)
   1.285 +{
   1.286 +	Uint32 id;
   1.287 +
   1.288 +	if ( thread ) {
   1.289 +		id = thread->threadid;
   1.290 +	} else {
   1.291 +		id = SDL_ThreadID();
   1.292 +	}
   1.293 +	return(id);
   1.294 +}
   1.295 +
   1.296 +void SDL_KillThread(SDL_Thread *thread)
   1.297 +{
   1.298 +	if ( thread ) {
   1.299 +		SDL_SYS_KillThread(thread);
   1.300 +		SDL_WaitThread(thread, NULL);
   1.301 +	}
   1.302 +}
   1.303 +