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