src/thread/SDL_thread.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. SDL_ThreadsInit
  2. SDL_ThreadsQuit
  3. SDL_AddThread
  4. SDL_DelThread
  5. SDL_GetErrBuf
  6. SDL_RunThread
  7. SDL_CreateThread
  8. SDL_WaitThread
  9. SDL_GetThreadID
  10. SDL_KillThread

   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: SDL_thread.c,v 1.2.2.9 2001/02/10 07:20:04 hercules Exp $";
  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 SDL_mutex *thread_lock = NULL;
  49 int _creating_thread_lock = 0;
  50 
  51 int SDL_ThreadsInit(void)
     /* [<][>][^][v][top][bottom][index][help] */
  52 {
  53         int retval;
  54 
  55         retval = 0;
  56         /* Set the thread lock creation flag so that we can reuse an
  57            existing lock on the system - since this mutex never gets
  58            destroyed (see SDL_ThreadsQuit()), we want to reuse it.
  59         */
  60         _creating_thread_lock = 1;
  61         thread_lock = SDL_CreateMutex();
  62         _creating_thread_lock = 0;
  63         if ( thread_lock == NULL ) {
  64                 retval = -1;
  65         }
  66         return(retval);
  67 }
  68 
  69 /* This should never be called...
  70    If this is called by SDL_Quit(), we don't know whether or not we should
  71    clean up threads here.  If any threads are still running after this call,
  72    they will no longer have access to any per-thread data.
  73  */
  74 void SDL_ThreadsQuit()
     /* [<][>][^][v][top][bottom][index][help] */
  75 {
  76         SDL_mutex *mutex;
  77 
  78         mutex = thread_lock;
  79         thread_lock = NULL;
  80         if ( mutex != NULL ) {
  81                 SDL_DestroyMutex(mutex);
  82         }
  83 }
  84 
  85 /* Routines for manipulating the thread list */
  86 static void SDL_AddThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
  87 {
  88         SDL_Thread **threads;
  89 
  90         /* WARNING:
  91            If the very first threads are created simultaneously, then
  92            there could be a race condition causing memory corruption.
  93            In practice, this isn't a problem because by definition there
  94            is only one thread running the first time this is called.
  95         */
  96         if ( thread_lock == NULL ) {
  97                 if ( SDL_ThreadsInit() < 0 ) {
  98                         return;
  99                 }
 100         }
 101         SDL_mutexP(thread_lock);
 102 
 103         /* Expand the list of threads, if necessary */
 104 #ifdef DEBUG_THREADS
 105         printf("Adding thread (%d already - %d max)\n",
 106                         SDL_numthreads, SDL_maxthreads);
 107 #endif
 108         if ( SDL_numthreads == SDL_maxthreads ) {
 109                 threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
 110                                               (sizeof *threads));
 111                 if ( threads == NULL ) {
 112                         SDL_OutOfMemory();
 113                         goto done;
 114                 }
 115                 memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
 116                 SDL_maxthreads += ARRAY_CHUNKSIZE;
 117                 if ( SDL_Threads ) {
 118                         free(SDL_Threads);
 119                 }
 120                 SDL_Threads = threads;
 121         }
 122         SDL_Threads[SDL_numthreads++] = thread;
 123 done:
 124         SDL_mutexV(thread_lock);
 125 }
 126 
 127 static void SDL_DelThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 128 {
 129         int i;
 130 
 131         if ( thread_lock ) {
 132                 SDL_mutexP(thread_lock);
 133                 for ( i=0; i<SDL_numthreads; ++i ) {
 134                         if ( thread == SDL_Threads[i] ) {
 135                                 break;
 136                         }
 137                 }
 138                 if ( i < SDL_numthreads ) {
 139                         --SDL_numthreads;
 140                         while ( i < SDL_numthreads ) {
 141                                 SDL_Threads[i] = SDL_Threads[i+1];
 142                                 ++i;
 143                         }
 144 #ifdef DEBUG_THREADS
 145                         printf("Deleting thread (%d left - %d max)\n",
 146                                         SDL_numthreads, SDL_maxthreads);
 147 #endif
 148                 }
 149                 SDL_mutexV(thread_lock);
 150         }
 151 }
 152 
 153 /* The default (non-thread-safe) global error variable */
 154 static SDL_error SDL_global_error;
 155 
 156 /* Routine to get the thread-specific error variable */
 157 SDL_error *SDL_GetErrBuf(void)
     /* [<][>][^][v][top][bottom][index][help] */
 158 {
 159         SDL_error *errbuf;
 160 
 161         errbuf = &SDL_global_error;
 162         if ( SDL_Threads ) {
 163                 int i;
 164                 Uint32 this_thread;
 165 
 166                 this_thread = SDL_ThreadID();
 167                 SDL_mutexP(thread_lock);
 168                 for ( i=0; i<SDL_numthreads; ++i ) {
 169                         if ( this_thread == SDL_Threads[i]->threadid ) {
 170                                 errbuf = &SDL_Threads[i]->errbuf;
 171                                 break;
 172                         }
 173                 }
 174                 SDL_mutexV(thread_lock);
 175         }
 176         return(errbuf);
 177 }
 178 
 179 
 180 /* Arguments and callback to setup and run the user thread function */
 181 typedef struct {
 182         int (*func)(void *);
 183         void *data;
 184         SDL_Thread *info;
 185         SDL_sem *wait;
 186 } thread_args;
 187 
 188 void SDL_RunThread(void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 189 {
 190         thread_args *args;
 191         int (*userfunc)(void *);
 192         void *userdata;
 193         int *statusloc;
 194 
 195         /* Perform any system-dependent setup
 196            - this function cannot fail, and cannot use SDL_SetError()
 197          */
 198         SDL_SYS_SetupThread();
 199 
 200         /* Get the thread id */
 201         args = (thread_args *)data;
 202         args->info->threadid = SDL_ThreadID();
 203 
 204         /* Figure out what function to run */
 205         userfunc = args->func;
 206         userdata = args->data;
 207         statusloc = &args->info->status;
 208 
 209         /* Wake up the parent thread */
 210         SDL_SemPost(args->wait);
 211 
 212         /* Run the function */
 213         *statusloc = userfunc(userdata);
 214 }
 215 
 216 SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 217 {
 218         SDL_Thread *thread;
 219         thread_args *args;
 220         int ret;
 221 
 222         /* Allocate memory for the thread info structure */
 223         thread = (SDL_Thread *)malloc(sizeof(*thread));
 224         if ( thread == NULL ) {
 225                 SDL_OutOfMemory();
 226                 return(NULL);
 227         }
 228         memset(thread, 0, (sizeof *thread));
 229         thread->status = -1;
 230 
 231         /* Set up the arguments for the thread */
 232         args = (thread_args *)malloc(sizeof(*args));
 233         if ( args == NULL ) {
 234                 SDL_OutOfMemory();
 235                 free(thread);
 236                 return(NULL);
 237         }
 238         args->func = fn;
 239         args->data = data;
 240         args->info = thread;
 241         args->wait = SDL_CreateSemaphore(0);
 242         if ( args->wait == NULL ) {
 243                 free(thread);
 244                 free(args);
 245                 return(NULL);
 246         }
 247 
 248         /* Add the thread to the list of available threads */
 249         SDL_AddThread(thread);
 250 
 251         /* Create the thread and go! */
 252         ret = SDL_SYS_CreateThread(thread, args);
 253         if ( ret >= 0 ) {
 254                 /* Wait for the thread function to use arguments */
 255                 SDL_SemWait(args->wait);
 256         } else {
 257                 /* Oops, failed.  Gotta free everything */
 258                 SDL_DelThread(thread);
 259                 free(thread);
 260                 thread = NULL;
 261         }
 262         SDL_DestroySemaphore(args->wait);
 263         free(args);
 264 
 265         /* Everything is running now */
 266         return(thread);
 267 }
 268 
 269 void SDL_WaitThread(SDL_Thread *thread, int *status)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271         if ( thread ) {
 272                 SDL_SYS_WaitThread(thread);
 273                 if ( status ) {
 274                         *status = thread->status;
 275                 }
 276                 SDL_DelThread(thread);
 277                 free(thread);
 278         }
 279 }
 280 
 281 Uint32 SDL_GetThreadID(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 282 {
 283         Uint32 id;
 284 
 285         if ( thread ) {
 286                 id = thread->threadid;
 287         } else {
 288                 id = SDL_ThreadID();
 289         }
 290         return(id);
 291 }
 292 
 293 void SDL_KillThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 294 {
 295         if ( thread ) {
 296                 SDL_SYS_KillThread(thread);
 297                 SDL_WaitThread(thread, NULL);
 298         }
 299 }
 300 

/* [<][>][^][v][top][bottom][index][help] */