diff options
Diffstat (limited to 'distrib/sdl-1.2.15/src/thread/SDL_thread.c')
-rw-r--r-- | distrib/sdl-1.2.15/src/thread/SDL_thread.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.15/src/thread/SDL_thread.c b/distrib/sdl-1.2.15/src/thread/SDL_thread.c new file mode 100644 index 0000000..250371d --- /dev/null +++ b/distrib/sdl-1.2.15/src/thread/SDL_thread.c @@ -0,0 +1,300 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + 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 + Lesser General Public License for more details. + + 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 + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* System independent thread management routines for SDL */ + +#include "SDL_mutex.h" +#include "SDL_thread.h" +#include "SDL_thread_c.h" +#include "SDL_systhread.h" + +#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 SDL_mutex *thread_lock = NULL; + +int SDL_ThreadsInit(void) +{ + int retval; + + retval = 0; + thread_lock = SDL_CreateMutex(); + if ( thread_lock == NULL ) { + retval = -1; + } + return(retval); +} + +/* 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. + */ +void SDL_ThreadsQuit(void) +{ + SDL_mutex *mutex; + + mutex = thread_lock; + thread_lock = NULL; + if ( mutex != NULL ) { + SDL_DestroyMutex(mutex); + } +} + +/* Routines for manipulating the thread list */ +static void SDL_AddThread(SDL_Thread *thread) +{ + /* 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 ) { + if ( SDL_ThreadsInit() < 0 ) { + return; + } + } + SDL_mutexP(thread_lock); + + /* Expand the list of threads, if necessary */ +#ifdef DEBUG_THREADS + printf("Adding thread (%d already - %d max)\n", + SDL_numthreads, SDL_maxthreads); +#endif + if ( SDL_numthreads == SDL_maxthreads ) { + SDL_Thread **threads; + threads = (SDL_Thread **)SDL_realloc(SDL_Threads, + (SDL_maxthreads+ARRAY_CHUNKSIZE)*(sizeof *threads)); + if ( threads == NULL ) { + SDL_OutOfMemory(); + goto done; + } + SDL_maxthreads += ARRAY_CHUNKSIZE; + SDL_Threads = threads; + } + SDL_Threads[SDL_numthreads++] = thread; +done: + SDL_mutexV(thread_lock); +} + +static void SDL_DelThread(SDL_Thread *thread) +{ + int i; + + if ( !thread_lock ) { + return; + } + SDL_mutexP(thread_lock); + for ( i=0; i<SDL_numthreads; ++i ) { + if ( thread == SDL_Threads[i] ) { + break; + } + } + if ( i < SDL_numthreads ) { + if ( --SDL_numthreads > 0 ) { + while ( i < SDL_numthreads ) { + SDL_Threads[i] = SDL_Threads[i+1]; + ++i; + } + } else { + SDL_maxthreads = 0; + SDL_free(SDL_Threads); + SDL_Threads = NULL; + } +#ifdef DEBUG_THREADS + printf("Deleting thread (%d left - %d max)\n", + SDL_numthreads, SDL_maxthreads); +#endif + } + SDL_mutexV(thread_lock); + +#if 0 /* There could be memory corruption if another thread is starting */ + if ( SDL_Threads == NULL ) { + SDL_ThreadsQuit(); + } +#endif +} + +/* The default (non-thread-safe) global error variable */ +static SDL_error SDL_global_error; + +/* Routine to get the thread-specific error variable */ +SDL_error *SDL_GetErrBuf(void) +{ + SDL_error *errbuf; + + errbuf = &SDL_global_error; + if ( SDL_Threads ) { + int i; + Uint32 this_thread; + + this_thread = SDL_ThreadID(); + SDL_mutexP(thread_lock); + for ( i=0; i<SDL_numthreads; ++i ) { + if ( this_thread == SDL_Threads[i]->threadid ) { + errbuf = &SDL_Threads[i]->errbuf; + break; + } + } + SDL_mutexV(thread_lock); + } + return(errbuf); +} + + +/* Arguments and callback to setup and run the user thread function */ +typedef struct { + int (SDLCALL *func)(void *); + void *data; + SDL_Thread *info; + SDL_sem *wait; +} thread_args; + +void SDL_RunThread(void *data) +{ + thread_args *args; + int (SDLCALL *userfunc)(void *); + void *userdata; + int *statusloc; + + /* Perform any system-dependent setup + - this function cannot fail, and cannot use SDL_SetError() + */ + SDL_SYS_SetupThread(); + + /* Get the thread id */ + args = (thread_args *)data; + args->info->threadid = SDL_ThreadID(); + + /* Figure out what function to run */ + userfunc = args->func; + userdata = args->data; + statusloc = &args->info->status; + + /* Wake up the parent thread */ + SDL_SemPost(args->wait); + + /* Run the function */ + *statusloc = userfunc(userdata); +} + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +#undef SDL_CreateThread +DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (SDLCALL *fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) +#else +DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (SDLCALL *fn)(void *), void *data) +#endif +{ + SDL_Thread *thread; + thread_args *args; + int ret; + + /* Allocate memory for the thread info structure */ + thread = (SDL_Thread *)SDL_malloc(sizeof(*thread)); + if ( thread == NULL ) { + SDL_OutOfMemory(); + return(NULL); + } + SDL_memset(thread, 0, (sizeof *thread)); + thread->status = -1; + + /* Set up the arguments for the thread */ + args = (thread_args *)SDL_malloc(sizeof(*args)); + if ( args == NULL ) { + SDL_OutOfMemory(); + SDL_free(thread); + return(NULL); + } + args->func = fn; + args->data = data; + args->info = thread; + args->wait = SDL_CreateSemaphore(0); + if ( args->wait == NULL ) { + SDL_free(thread); + SDL_free(args); + return(NULL); + } + + /* Add the thread to the list of available threads */ + SDL_AddThread(thread); + + /* Create the thread and go! */ +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread); +#else + ret = SDL_SYS_CreateThread(thread, args); +#endif + if ( ret >= 0 ) { + /* Wait for the thread function to use arguments */ + SDL_SemWait(args->wait); + } else { + /* Oops, failed. Gotta free everything */ + SDL_DelThread(thread); + SDL_free(thread); + thread = NULL; + } + SDL_DestroySemaphore(args->wait); + SDL_free(args); + + /* Everything is running now */ + return(thread); +} + +void SDL_WaitThread(SDL_Thread *thread, int *status) +{ + if ( thread ) { + SDL_SYS_WaitThread(thread); + if ( status ) { + *status = thread->status; + } + SDL_DelThread(thread); + SDL_free(thread); + } +} + +Uint32 SDL_GetThreadID(SDL_Thread *thread) +{ + Uint32 id; + + if ( thread ) { + id = thread->threadid; + } else { + id = SDL_ThreadID(); + } + return(id); +} + +void SDL_KillThread(SDL_Thread *thread) +{ + if ( thread ) { + SDL_SYS_KillThread(thread); + SDL_WaitThread(thread, NULL); + } +} + |