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

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