src/thread/SDL_thread.c
author Sam Lantinga
Wed, 10 Jul 2013 02:32:04 -0700
changeset 7391 a29895dc5e9a
parent 7191 75360622e65f
child 7393 358696c354a8
permissions -rw-r--r--
Implemented an API for thread-local storage: SDL_TLSCreate(), SDL_TLSSet(), SDL_TLSGet()
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* System independent thread management routines for SDL */
    24 
    25 #include "SDL_thread.h"
    26 #include "SDL_thread_c.h"
    27 #include "SDL_systhread.h"
    28 #include "../SDL_error_c.h"
    29 
    30 
    31 /* Routine to get the thread-specific error variable */
    32 SDL_error *
    33 SDL_GetErrBuf(void)
    34 {
    35     static SDL_SpinLock spinlock;
    36     static SDL_bool tls_being_created;
    37     static SDL_TLSID tls_errbuf;
    38     static SDL_error SDL_global_errbuf;
    39     SDL_error *errbuf;
    40 
    41     if (!tls_errbuf && !tls_being_created) {
    42         SDL_AtomicLock(&spinlock);
    43         if (!tls_errbuf) {
    44             /* SDL_TLSCreate() could fail and call SDL_SetError() */
    45             tls_being_created = SDL_TRUE;
    46             tls_errbuf = SDL_TLSCreate();
    47             tls_being_created = SDL_FALSE;
    48         }
    49         SDL_AtomicUnlock(&spinlock);
    50     }
    51     if (!tls_errbuf) {
    52         return &SDL_global_errbuf;
    53     }
    54 
    55     errbuf = SDL_TLSGet(tls_errbuf);
    56     if (!errbuf) {
    57         errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
    58         if (!errbuf) {
    59             return &SDL_global_errbuf;
    60         }
    61         SDL_zerop(errbuf);
    62         SDL_TLSSet(tls_errbuf, errbuf);
    63     }
    64     return errbuf;
    65 }
    66 
    67 
    68 /* Arguments and callback to setup and run the user thread function */
    69 typedef struct
    70 {
    71     int (SDLCALL * func) (void *);
    72     void *data;
    73     SDL_Thread *info;
    74     SDL_sem *wait;
    75 } thread_args;
    76 
    77 void
    78 SDL_RunThread(void *data)
    79 {
    80     thread_args *args = (thread_args *) data;
    81     int (SDLCALL * userfunc) (void *) = args->func;
    82     void *userdata = args->data;
    83     int *statusloc = &args->info->status;
    84 
    85     /* Perform any system-dependent setup
    86        - this function cannot fail, and cannot use SDL_SetError()
    87      */
    88     SDL_SYS_SetupThread(args->info->name);
    89 
    90     /* Get the thread id */
    91     args->info->threadid = SDL_ThreadID();
    92 
    93     /* Wake up the parent thread */
    94     SDL_SemPost(args->wait);
    95 
    96     /* Run the function */
    97     *statusloc = userfunc(userdata);
    98 }
    99 
   100 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   101 #undef SDL_CreateThread
   102 DECLSPEC SDL_Thread *SDLCALL
   103 SDL_CreateThread(int (SDLCALL * fn) (void *),
   104                  const char *name, void *data,
   105                  pfnSDL_CurrentBeginThread pfnBeginThread,
   106                  pfnSDL_CurrentEndThread pfnEndThread)
   107 #else
   108 DECLSPEC SDL_Thread *SDLCALL
   109 SDL_CreateThread(int (SDLCALL * fn) (void *),
   110                  const char *name, void *data)
   111 #endif
   112 {
   113     SDL_Thread *thread;
   114     thread_args *args;
   115     int ret;
   116 
   117     /* Allocate memory for the thread info structure */
   118     thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
   119     if (thread == NULL) {
   120         SDL_OutOfMemory();
   121         return (NULL);
   122     }
   123     SDL_memset(thread, 0, (sizeof *thread));
   124     thread->status = -1;
   125 
   126     /* Set up the arguments for the thread */
   127     if (name != NULL) {
   128         thread->name = SDL_strdup(name);
   129         if (thread->name == NULL) {
   130             SDL_OutOfMemory();
   131             SDL_free(thread);
   132             return (NULL);
   133         }
   134     }
   135 
   136     /* Set up the arguments for the thread */
   137     args = (thread_args *) SDL_malloc(sizeof(*args));
   138     if (args == NULL) {
   139         SDL_OutOfMemory();
   140         SDL_free(thread->name);
   141         SDL_free(thread);
   142         return (NULL);
   143     }
   144     args->func = fn;
   145     args->data = data;
   146     args->info = thread;
   147     args->wait = SDL_CreateSemaphore(0);
   148     if (args->wait == NULL) {
   149         SDL_free(thread->name);
   150         SDL_free(thread);
   151         SDL_free(args);
   152         return (NULL);
   153     }
   154 
   155     /* Create the thread and go! */
   156 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
   157     ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
   158 #else
   159     ret = SDL_SYS_CreateThread(thread, args);
   160 #endif
   161     if (ret >= 0) {
   162         /* Wait for the thread function to use arguments */
   163         SDL_SemWait(args->wait);
   164     } else {
   165         /* Oops, failed.  Gotta free everything */
   166         SDL_free(thread->name);
   167         SDL_free(thread);
   168         thread = NULL;
   169     }
   170     SDL_DestroySemaphore(args->wait);
   171     SDL_free(args);
   172 
   173     /* Everything is running now */
   174     return (thread);
   175 }
   176 
   177 SDL_threadID
   178 SDL_GetThreadID(SDL_Thread * thread)
   179 {
   180     SDL_threadID id;
   181 
   182     if (thread) {
   183         id = thread->threadid;
   184     } else {
   185         id = SDL_ThreadID();
   186     }
   187     return id;
   188 }
   189 
   190 const char *
   191 SDL_GetThreadName(SDL_Thread * thread)
   192 {
   193     return thread->name;
   194 }
   195 
   196 int
   197 SDL_SetThreadPriority(SDL_ThreadPriority priority)
   198 {
   199     return SDL_SYS_SetThreadPriority(priority);
   200 }
   201 
   202 void
   203 SDL_WaitThread(SDL_Thread * thread, int *status)
   204 {
   205     if (thread) {
   206         SDL_SYS_WaitThread(thread);
   207         if (status) {
   208             *status = thread->status;
   209         }
   210         SDL_free(thread->name);
   211         SDL_free(thread);
   212     }
   213 }
   214 
   215 /* vi: set ts=4 sw=4 expandtab: */