aboutsummaryrefslogtreecommitdiffstats
path: root/distrib/sdl-1.2.15/src/thread/SDL_thread.c
diff options
context:
space:
mode:
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.c300
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);
+ }
+}
+