src/thread/SDL_thread.c
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
equal deleted inserted replaced
1667:1fddae038bc8 1668:4da1ee79c9af
    37 static int SDL_numthreads = 0;
    37 static int SDL_numthreads = 0;
    38 static SDL_Thread **SDL_Threads = NULL;
    38 static SDL_Thread **SDL_Threads = NULL;
    39 static SDL_mutex *thread_lock = NULL;
    39 static SDL_mutex *thread_lock = NULL;
    40 
    40 
    41 int
    41 int
    42 SDL_ThreadsInit (void)
    42 SDL_ThreadsInit(void)
    43 {
    43 {
    44     int retval;
    44     int retval;
    45 
    45 
    46     retval = 0;
    46     retval = 0;
    47     thread_lock = SDL_CreateMutex ();
    47     thread_lock = SDL_CreateMutex();
    48     if (thread_lock == NULL) {
    48     if (thread_lock == NULL) {
    49         retval = -1;
    49         retval = -1;
    50     }
    50     }
    51     return (retval);
    51     return (retval);
    52 }
    52 }
    55    If this is called by SDL_Quit(), we don't know whether or not we should
    55    If this is called by SDL_Quit(), we don't know whether or not we should
    56    clean up threads here.  If any threads are still running after this call,
    56    clean up threads here.  If any threads are still running after this call,
    57    they will no longer have access to any per-thread data.
    57    they will no longer have access to any per-thread data.
    58  */
    58  */
    59 void
    59 void
    60 SDL_ThreadsQuit (void)
    60 SDL_ThreadsQuit(void)
    61 {
    61 {
    62     SDL_mutex *mutex;
    62     SDL_mutex *mutex;
    63 
    63 
    64     mutex = thread_lock;
    64     mutex = thread_lock;
    65     thread_lock = NULL;
    65     thread_lock = NULL;
    66     if (mutex != NULL) {
    66     if (mutex != NULL) {
    67         SDL_DestroyMutex (mutex);
    67         SDL_DestroyMutex(mutex);
    68     }
    68     }
    69 }
    69 }
    70 
    70 
    71 /* Routines for manipulating the thread list */
    71 /* Routines for manipulating the thread list */
    72 static void
    72 static void
    73 SDL_AddThread (SDL_Thread * thread)
    73 SDL_AddThread(SDL_Thread * thread)
    74 {
    74 {
    75     /* WARNING:
    75     /* WARNING:
    76        If the very first threads are created simultaneously, then
    76        If the very first threads are created simultaneously, then
    77        there could be a race condition causing memory corruption.
    77        there could be a race condition causing memory corruption.
    78        In practice, this isn't a problem because by definition there
    78        In practice, this isn't a problem because by definition there
    79        is only one thread running the first time this is called.
    79        is only one thread running the first time this is called.
    80      */
    80      */
    81     if (!thread_lock) {
    81     if (!thread_lock) {
    82         if (SDL_ThreadsInit () < 0) {
    82         if (SDL_ThreadsInit() < 0) {
    83             return;
    83             return;
    84         }
    84         }
    85     }
    85     }
    86     SDL_mutexP (thread_lock);
    86     SDL_mutexP(thread_lock);
    87 
    87 
    88     /* Expand the list of threads, if necessary */
    88     /* Expand the list of threads, if necessary */
    89 #ifdef DEBUG_THREADS
    89 #ifdef DEBUG_THREADS
    90     printf ("Adding thread (%d already - %d max)\n",
    90     printf("Adding thread (%d already - %d max)\n",
    91             SDL_numthreads, SDL_maxthreads);
    91            SDL_numthreads, SDL_maxthreads);
    92 #endif
    92 #endif
    93     if (SDL_numthreads == SDL_maxthreads) {
    93     if (SDL_numthreads == SDL_maxthreads) {
    94         SDL_Thread **threads;
    94         SDL_Thread **threads;
    95         threads = (SDL_Thread **) SDL_realloc (SDL_Threads,
    95         threads = (SDL_Thread **) SDL_realloc(SDL_Threads,
    96                                                (SDL_maxthreads +
    96                                               (SDL_maxthreads +
    97                                                 ARRAY_CHUNKSIZE) *
    97                                                ARRAY_CHUNKSIZE) *
    98                                                (sizeof *threads));
    98                                               (sizeof *threads));
    99         if (threads == NULL) {
    99         if (threads == NULL) {
   100             SDL_OutOfMemory ();
   100             SDL_OutOfMemory();
   101             goto done;
   101             goto done;
   102         }
   102         }
   103         SDL_maxthreads += ARRAY_CHUNKSIZE;
   103         SDL_maxthreads += ARRAY_CHUNKSIZE;
   104         SDL_Threads = threads;
   104         SDL_Threads = threads;
   105     }
   105     }
   106     SDL_Threads[SDL_numthreads++] = thread;
   106     SDL_Threads[SDL_numthreads++] = thread;
   107   done:
   107   done:
   108     SDL_mutexV (thread_lock);
   108     SDL_mutexV(thread_lock);
   109 }
   109 }
   110 
   110 
   111 static void
   111 static void
   112 SDL_DelThread (SDL_Thread * thread)
   112 SDL_DelThread(SDL_Thread * thread)
   113 {
   113 {
   114     int i;
   114     int i;
   115 
   115 
   116     if (!thread_lock) {
   116     if (!thread_lock) {
   117         return;
   117         return;
   118     }
   118     }
   119     SDL_mutexP (thread_lock);
   119     SDL_mutexP(thread_lock);
   120     for (i = 0; i < SDL_numthreads; ++i) {
   120     for (i = 0; i < SDL_numthreads; ++i) {
   121         if (thread == SDL_Threads[i]) {
   121         if (thread == SDL_Threads[i]) {
   122             break;
   122             break;
   123         }
   123         }
   124     }
   124     }
   128                 SDL_Threads[i] = SDL_Threads[i + 1];
   128                 SDL_Threads[i] = SDL_Threads[i + 1];
   129                 ++i;
   129                 ++i;
   130             }
   130             }
   131         } else {
   131         } else {
   132             SDL_maxthreads = 0;
   132             SDL_maxthreads = 0;
   133             SDL_free (SDL_Threads);
   133             SDL_free(SDL_Threads);
   134             SDL_Threads = NULL;
   134             SDL_Threads = NULL;
   135         }
   135         }
   136 #ifdef DEBUG_THREADS
   136 #ifdef DEBUG_THREADS
   137         printf ("Deleting thread (%d left - %d max)\n",
   137         printf("Deleting thread (%d left - %d max)\n",
   138                 SDL_numthreads, SDL_maxthreads);
   138                SDL_numthreads, SDL_maxthreads);
   139 #endif
   139 #endif
   140     }
   140     }
   141     SDL_mutexV (thread_lock);
   141     SDL_mutexV(thread_lock);
   142 
   142 
   143     if (SDL_Threads == NULL) {
   143     if (SDL_Threads == NULL) {
   144         SDL_ThreadsQuit ();
   144         SDL_ThreadsQuit();
   145     }
   145     }
   146 }
   146 }
   147 
   147 
   148 /* The default (non-thread-safe) global error variable */
   148 /* The default (non-thread-safe) global error variable */
   149 static SDL_error SDL_global_error;
   149 static SDL_error SDL_global_error;
   150 
   150 
   151 /* Routine to get the thread-specific error variable */
   151 /* Routine to get the thread-specific error variable */
   152 SDL_error *
   152 SDL_error *
   153 SDL_GetErrBuf (void)
   153 SDL_GetErrBuf(void)
   154 {
   154 {
   155     SDL_error *errbuf;
   155     SDL_error *errbuf;
   156 
   156 
   157     errbuf = &SDL_global_error;
   157     errbuf = &SDL_global_error;
   158     if (SDL_Threads) {
   158     if (SDL_Threads) {
   159         int i;
   159         int i;
   160         Uint32 this_thread;
   160         Uint32 this_thread;
   161 
   161 
   162         this_thread = SDL_ThreadID ();
   162         this_thread = SDL_ThreadID();
   163         SDL_mutexP (thread_lock);
   163         SDL_mutexP(thread_lock);
   164         for (i = 0; i < SDL_numthreads; ++i) {
   164         for (i = 0; i < SDL_numthreads; ++i) {
   165             if (this_thread == SDL_Threads[i]->threadid) {
   165             if (this_thread == SDL_Threads[i]->threadid) {
   166                 errbuf = &SDL_Threads[i]->errbuf;
   166                 errbuf = &SDL_Threads[i]->errbuf;
   167                 break;
   167                 break;
   168             }
   168             }
   169         }
   169         }
   170         SDL_mutexV (thread_lock);
   170         SDL_mutexV(thread_lock);
   171     }
   171     }
   172     return (errbuf);
   172     return (errbuf);
   173 }
   173 }
   174 
   174 
   175 
   175 
   181     SDL_Thread *info;
   181     SDL_Thread *info;
   182     SDL_sem *wait;
   182     SDL_sem *wait;
   183 } thread_args;
   183 } thread_args;
   184 
   184 
   185 void
   185 void
   186 SDL_RunThread (void *data)
   186 SDL_RunThread(void *data)
   187 {
   187 {
   188     thread_args *args;
   188     thread_args *args;
   189     int (SDLCALL * userfunc) (void *);
   189     int (SDLCALL * userfunc) (void *);
   190     void *userdata;
   190     void *userdata;
   191     int *statusloc;
   191     int *statusloc;
   192 
   192 
   193     /* Perform any system-dependent setup
   193     /* Perform any system-dependent setup
   194        - this function cannot fail, and cannot use SDL_SetError()
   194        - this function cannot fail, and cannot use SDL_SetError()
   195      */
   195      */
   196     SDL_SYS_SetupThread ();
   196     SDL_SYS_SetupThread();
   197 
   197 
   198     /* Get the thread id */
   198     /* Get the thread id */
   199     args = (thread_args *) data;
   199     args = (thread_args *) data;
   200     args->info->threadid = SDL_ThreadID ();
   200     args->info->threadid = SDL_ThreadID();
   201 
   201 
   202     /* Figure out what function to run */
   202     /* Figure out what function to run */
   203     userfunc = args->func;
   203     userfunc = args->func;
   204     userdata = args->data;
   204     userdata = args->data;
   205     statusloc = &args->info->status;
   205     statusloc = &args->info->status;
   206 
   206 
   207     /* Wake up the parent thread */
   207     /* Wake up the parent thread */
   208     SDL_SemPost (args->wait);
   208     SDL_SemPost(args->wait);
   209 
   209 
   210     /* Run the function */
   210     /* Run the function */
   211     *statusloc = userfunc (userdata);
   211     *statusloc = userfunc(userdata);
   212 }
   212 }
   213 
   213 
   214 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   214 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   215 #undef SDL_CreateThread
   215 #undef SDL_CreateThread
   216 DECLSPEC SDL_Thread *SDLCALL
   216 DECLSPEC SDL_Thread *SDLCALL
   217 SDL_CreateThread (int (SDLCALL * fn) (void *), void *data,
   217 SDL_CreateThread(int (SDLCALL * fn) (void *), void *data,
   218                   pfnSDL_CurrentBeginThread pfnBeginThread,
   218                  pfnSDL_CurrentBeginThread pfnBeginThread,
   219                   pfnSDL_CurrentEndThread pfnEndThread)
   219                  pfnSDL_CurrentEndThread pfnEndThread)
   220 #else
   220 #else
   221 DECLSPEC SDL_Thread *SDLCALL
   221 DECLSPEC SDL_Thread *SDLCALL
   222 SDL_CreateThread (int (SDLCALL * fn) (void *), void *data)
   222 SDL_CreateThread(int (SDLCALL * fn) (void *), void *data)
   223 #endif
   223 #endif
   224 {
   224 {
   225     SDL_Thread *thread;
   225     SDL_Thread *thread;
   226     thread_args *args;
   226     thread_args *args;
   227     int ret;
   227     int ret;
   228 
   228 
   229     /* Allocate memory for the thread info structure */
   229     /* Allocate memory for the thread info structure */
   230     thread = (SDL_Thread *) SDL_malloc (sizeof (*thread));
   230     thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
   231     if (thread == NULL) {
   231     if (thread == NULL) {
   232         SDL_OutOfMemory ();
   232         SDL_OutOfMemory();
   233         return (NULL);
   233         return (NULL);
   234     }
   234     }
   235     SDL_memset (thread, 0, (sizeof *thread));
   235     SDL_memset(thread, 0, (sizeof *thread));
   236     thread->status = -1;
   236     thread->status = -1;
   237 
   237 
   238     /* Set up the arguments for the thread */
   238     /* Set up the arguments for the thread */
   239     args = (thread_args *) SDL_malloc (sizeof (*args));
   239     args = (thread_args *) SDL_malloc(sizeof(*args));
   240     if (args == NULL) {
   240     if (args == NULL) {
   241         SDL_OutOfMemory ();
   241         SDL_OutOfMemory();
   242         SDL_free (thread);
   242         SDL_free(thread);
   243         return (NULL);
   243         return (NULL);
   244     }
   244     }
   245     args->func = fn;
   245     args->func = fn;
   246     args->data = data;
   246     args->data = data;
   247     args->info = thread;
   247     args->info = thread;
   248     args->wait = SDL_CreateSemaphore (0);
   248     args->wait = SDL_CreateSemaphore(0);
   249     if (args->wait == NULL) {
   249     if (args->wait == NULL) {
   250         SDL_free (thread);
   250         SDL_free(thread);
   251         SDL_free (args);
   251         SDL_free(args);
   252         return (NULL);
   252         return (NULL);
   253     }
   253     }
   254 
   254 
   255     /* Add the thread to the list of available threads */
   255     /* Add the thread to the list of available threads */
   256     SDL_AddThread (thread);
   256     SDL_AddThread(thread);
   257 
   257 
   258     /* Create the thread and go! */
   258     /* Create the thread and go! */
   259 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   259 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   260     ret = SDL_SYS_CreateThread (thread, args, pfnBeginThread, pfnEndThread);
   260     ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
   261 #else
   261 #else
   262     ret = SDL_SYS_CreateThread (thread, args);
   262     ret = SDL_SYS_CreateThread(thread, args);
   263 #endif
   263 #endif
   264     if (ret >= 0) {
   264     if (ret >= 0) {
   265         /* Wait for the thread function to use arguments */
   265         /* Wait for the thread function to use arguments */
   266         SDL_SemWait (args->wait);
   266         SDL_SemWait(args->wait);
   267     } else {
   267     } else {
   268         /* Oops, failed.  Gotta free everything */
   268         /* Oops, failed.  Gotta free everything */
   269         SDL_DelThread (thread);
   269         SDL_DelThread(thread);
   270         SDL_free (thread);
   270         SDL_free(thread);
   271         thread = NULL;
   271         thread = NULL;
   272     }
   272     }
   273     SDL_DestroySemaphore (args->wait);
   273     SDL_DestroySemaphore(args->wait);
   274     SDL_free (args);
   274     SDL_free(args);
   275 
   275 
   276     /* Everything is running now */
   276     /* Everything is running now */
   277     return (thread);
   277     return (thread);
   278 }
   278 }
   279 
   279 
   280 void
   280 void
   281 SDL_WaitThread (SDL_Thread * thread, int *status)
   281 SDL_WaitThread(SDL_Thread * thread, int *status)
   282 {
   282 {
   283     if (thread) {
   283     if (thread) {
   284         SDL_SYS_WaitThread (thread);
   284         SDL_SYS_WaitThread(thread);
   285         if (status) {
   285         if (status) {
   286             *status = thread->status;
   286             *status = thread->status;
   287         }
   287         }
   288         SDL_DelThread (thread);
   288         SDL_DelThread(thread);
   289         SDL_free (thread);
   289         SDL_free(thread);
   290     }
   290     }
   291 }
   291 }
   292 
   292 
   293 Uint32
   293 Uint32
   294 SDL_GetThreadID (SDL_Thread * thread)
   294 SDL_GetThreadID(SDL_Thread * thread)
   295 {
   295 {
   296     Uint32 id;
   296     Uint32 id;
   297 
   297 
   298     if (thread) {
   298     if (thread) {
   299         id = thread->threadid;
   299         id = thread->threadid;
   300     } else {
   300     } else {
   301         id = SDL_ThreadID ();
   301         id = SDL_ThreadID();
   302     }
   302     }
   303     return (id);
   303     return (id);
   304 }
   304 }
   305 
   305 
   306 void
   306 void
   307 SDL_KillThread (SDL_Thread * thread)
   307 SDL_KillThread(SDL_Thread * thread)
   308 {
   308 {
   309     if (thread) {
   309     if (thread) {
   310         SDL_SYS_KillThread (thread);
   310         SDL_SYS_KillThread(thread);
   311         SDL_WaitThread (thread, NULL);
   311         SDL_WaitThread(thread, NULL);
   312     }
   312     }
   313 }
   313 }
   314 
   314 
   315 /* vi: set ts=4 sw=4 expandtab: */
   315 /* vi: set ts=4 sw=4 expandtab: */