src/thread/SDL_thread.c
author Ryan C. Gordon
Tue, 12 Apr 2016 16:45:10 -0400
changeset 10146 471eb08040ce
parent 10145 cd87106d1d47
child 10617 346c02ff71b6
permissions -rw-r--r--
threads: Move SDL's own thread creation to a new internal API.

This allows us to set an explicit stack size (overriding the system default
and the global hint an app might have set), and remove all the macro salsa
for dealing with _beginthreadex and such, as internal threads always set those
to NULL anyhow.

I've taken some guesses on reasonable (and tiny!) stack sizes for our
internal threads, but some of these might turn out to be too small in
practice and need an increase. Most of them are simple functions, though.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 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
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@0
    22
slouken@0
    23
/* System independent thread management routines for SDL */
slouken@0
    24
icculus@7978
    25
#include "SDL_assert.h"
slouken@0
    26
#include "SDL_thread.h"
slouken@0
    27
#include "SDL_thread_c.h"
slouken@0
    28
#include "SDL_systhread.h"
icculus@10145
    29
#include "SDL_hints.h"
slouken@6044
    30
#include "../SDL_error_c.h"
slouken@0
    31
slouken@0
    32
slouken@7393
    33
SDL_TLSID
slouken@7393
    34
SDL_TLSCreate()
slouken@7393
    35
{
slouken@7393
    36
    static SDL_atomic_t SDL_tls_id;
slouken@7393
    37
    return SDL_AtomicIncRef(&SDL_tls_id)+1;
slouken@7393
    38
}
slouken@7393
    39
slouken@7393
    40
void *
slouken@7393
    41
SDL_TLSGet(SDL_TLSID id)
slouken@7393
    42
{
slouken@7393
    43
    SDL_TLSData *storage;
slouken@7393
    44
slouken@7393
    45
    storage = SDL_SYS_GetTLSData();
slouken@7393
    46
    if (!storage || id == 0 || id > storage->limit) {
slouken@7393
    47
        return NULL;
slouken@7393
    48
    }
slouken@7393
    49
    return storage->array[id-1].data;
slouken@7393
    50
}
slouken@7393
    51
slouken@7393
    52
int
slouken@7393
    53
SDL_TLSSet(SDL_TLSID id, const void *value, void (*destructor)(void *))
slouken@7393
    54
{
slouken@7393
    55
    SDL_TLSData *storage;
slouken@7393
    56
slouken@7393
    57
    if (id == 0) {
slouken@7393
    58
        return SDL_InvalidParamError("id");
slouken@7393
    59
    }
slouken@7393
    60
slouken@7393
    61
    storage = SDL_SYS_GetTLSData();
icculus@7482
    62
    if (!storage || (id > storage->limit)) {
icculus@7482
    63
        unsigned int i, oldlimit, newlimit;
slouken@7393
    64
slouken@7393
    65
        oldlimit = storage ? storage->limit : 0;
slouken@7393
    66
        newlimit = (id + TLS_ALLOC_CHUNKSIZE);
slouken@7393
    67
        storage = (SDL_TLSData *)SDL_realloc(storage, sizeof(*storage)+(newlimit-1)*sizeof(storage->array[0]));
slouken@7393
    68
        if (!storage) {
slouken@7393
    69
            return SDL_OutOfMemory();
slouken@7393
    70
        }
slouken@7393
    71
        storage->limit = newlimit;
slouken@7393
    72
        for (i = oldlimit; i < newlimit; ++i) {
slouken@7393
    73
            storage->array[i].data = NULL;
slouken@7393
    74
            storage->array[i].destructor = NULL;
slouken@7393
    75
        }
slouken@7393
    76
        if (SDL_SYS_SetTLSData(storage) != 0) {
slouken@7393
    77
            return -1;
slouken@7393
    78
        }
slouken@7393
    79
    }
slouken@7393
    80
slouken@7393
    81
    storage->array[id-1].data = SDL_const_cast(void*, value);
slouken@7393
    82
    storage->array[id-1].destructor = destructor;
slouken@7393
    83
    return 0;
slouken@7393
    84
}
slouken@7393
    85
slouken@7393
    86
static void
slouken@7393
    87
SDL_TLSCleanup()
slouken@7393
    88
{
slouken@7393
    89
    SDL_TLSData *storage;
slouken@7393
    90
slouken@7393
    91
    storage = SDL_SYS_GetTLSData();
slouken@7393
    92
    if (storage) {
icculus@7484
    93
        unsigned int i;
slouken@7393
    94
        for (i = 0; i < storage->limit; ++i) {
slouken@7393
    95
            if (storage->array[i].destructor) {
slouken@7393
    96
                storage->array[i].destructor(storage->array[i].data);
slouken@7393
    97
            }
slouken@7393
    98
        }
slouken@7393
    99
        SDL_SYS_SetTLSData(NULL);
slouken@7393
   100
        SDL_free(storage);
slouken@7393
   101
    }
slouken@7393
   102
}
slouken@7393
   103
slouken@7393
   104
slouken@7393
   105
/* This is a generic implementation of thread-local storage which doesn't
slouken@7393
   106
   require additional OS support.
slouken@7393
   107
slouken@7393
   108
   It is not especially efficient and doesn't clean up thread-local storage
slouken@7393
   109
   as threads exit.  If there is a real OS that doesn't support thread-local
slouken@7393
   110
   storage this implementation should be improved to be production quality.
slouken@7393
   111
*/
slouken@7393
   112
slouken@7393
   113
typedef struct SDL_TLSEntry {
slouken@7393
   114
    SDL_threadID thread;
slouken@7393
   115
    SDL_TLSData *storage;
slouken@7393
   116
    struct SDL_TLSEntry *next;
slouken@7393
   117
} SDL_TLSEntry;
slouken@7393
   118
slouken@7393
   119
static SDL_mutex *SDL_generic_TLS_mutex;
slouken@7393
   120
static SDL_TLSEntry *SDL_generic_TLS;
slouken@7393
   121
slouken@7393
   122
slouken@7393
   123
SDL_TLSData *
slouken@7393
   124
SDL_Generic_GetTLSData()
slouken@7393
   125
{
slouken@7393
   126
    SDL_threadID thread = SDL_ThreadID();
slouken@7393
   127
    SDL_TLSEntry *entry;
slouken@7393
   128
    SDL_TLSData *storage = NULL;
slouken@7393
   129
slouken@7730
   130
#if !SDL_THREADS_DISABLED
slouken@7393
   131
    if (!SDL_generic_TLS_mutex) {
slouken@7393
   132
        static SDL_SpinLock tls_lock;
slouken@7393
   133
        SDL_AtomicLock(&tls_lock);
slouken@7393
   134
        if (!SDL_generic_TLS_mutex) {
slouken@7393
   135
            SDL_mutex *mutex = SDL_CreateMutex();
slouken@7393
   136
            SDL_MemoryBarrierRelease();
slouken@7393
   137
            SDL_generic_TLS_mutex = mutex;
slouken@7393
   138
            if (!SDL_generic_TLS_mutex) {
slouken@7393
   139
                SDL_AtomicUnlock(&tls_lock);
slouken@7393
   140
                return NULL;
slouken@7393
   141
            }
slouken@7393
   142
        }
slouken@7393
   143
        SDL_AtomicUnlock(&tls_lock);
slouken@7393
   144
    }
slouken@7730
   145
#endif /* SDL_THREADS_DISABLED */
slouken@7393
   146
slouken@7393
   147
    SDL_MemoryBarrierAcquire();
slouken@7393
   148
    SDL_LockMutex(SDL_generic_TLS_mutex);
slouken@7393
   149
    for (entry = SDL_generic_TLS; entry; entry = entry->next) {
slouken@7393
   150
        if (entry->thread == thread) {
slouken@7393
   151
            storage = entry->storage;
slouken@7393
   152
            break;
slouken@7393
   153
        }
slouken@7393
   154
    }
slouken@7730
   155
#if !SDL_THREADS_DISABLED
slouken@7393
   156
    SDL_UnlockMutex(SDL_generic_TLS_mutex);
slouken@7730
   157
#endif
slouken@7393
   158
slouken@7393
   159
    return storage;
slouken@7393
   160
}
slouken@7393
   161
slouken@7393
   162
int
slouken@7393
   163
SDL_Generic_SetTLSData(SDL_TLSData *storage)
slouken@7393
   164
{
slouken@7393
   165
    SDL_threadID thread = SDL_ThreadID();
slouken@7393
   166
    SDL_TLSEntry *prev, *entry;
slouken@7393
   167
slouken@7393
   168
    /* SDL_Generic_GetTLSData() is always called first, so we can assume SDL_generic_TLS_mutex */
slouken@7393
   169
    SDL_LockMutex(SDL_generic_TLS_mutex);
slouken@7393
   170
    prev = NULL;
slouken@7393
   171
    for (entry = SDL_generic_TLS; entry; entry = entry->next) {
slouken@7393
   172
        if (entry->thread == thread) {
slouken@7393
   173
            if (storage) {
slouken@7393
   174
                entry->storage = storage;
slouken@7393
   175
            } else {
slouken@7393
   176
                if (prev) {
slouken@7393
   177
                    prev->next = entry->next;
slouken@7393
   178
                } else {
slouken@7393
   179
                    SDL_generic_TLS = entry->next;
slouken@7393
   180
                }
slouken@7393
   181
                SDL_free(entry);
slouken@7393
   182
            }
slouken@7393
   183
            break;
slouken@7393
   184
        }
slouken@7393
   185
        prev = entry;
slouken@7393
   186
    }
slouken@7393
   187
    if (!entry) {
slouken@7393
   188
        entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
slouken@7393
   189
        if (entry) {
slouken@7393
   190
            entry->thread = thread;
slouken@7393
   191
            entry->storage = storage;
slouken@7393
   192
            entry->next = SDL_generic_TLS;
slouken@7393
   193
            SDL_generic_TLS = entry;
slouken@7393
   194
        }
slouken@7393
   195
    }
slouken@7393
   196
    SDL_UnlockMutex(SDL_generic_TLS_mutex);
slouken@7393
   197
slouken@7393
   198
    if (!entry) {
slouken@7393
   199
        return SDL_OutOfMemory();
slouken@7393
   200
    }
slouken@7393
   201
    return 0;
slouken@7393
   202
}
slouken@7393
   203
slouken@0
   204
/* Routine to get the thread-specific error variable */
slouken@1895
   205
SDL_error *
slouken@1895
   206
SDL_GetErrBuf(void)
slouken@0
   207
{
slouken@7393
   208
    static SDL_SpinLock tls_lock;
slouken@7391
   209
    static SDL_bool tls_being_created;
slouken@7391
   210
    static SDL_TLSID tls_errbuf;
slouken@7391
   211
    static SDL_error SDL_global_errbuf;
slouken@7393
   212
    const SDL_error *ALLOCATION_IN_PROGRESS = (SDL_error *)-1;
slouken@1895
   213
    SDL_error *errbuf;
slouken@0
   214
slouken@7393
   215
    /* tls_being_created is there simply to prevent recursion if SDL_TLSCreate() fails.
slouken@7393
   216
       It also means it's possible for another thread to also use SDL_global_errbuf,
slouken@7393
   217
       but that's very unlikely and hopefully won't cause issues.
slouken@7393
   218
     */
slouken@7391
   219
    if (!tls_errbuf && !tls_being_created) {
slouken@7393
   220
        SDL_AtomicLock(&tls_lock);
slouken@7391
   221
        if (!tls_errbuf) {
slouken@7393
   222
            SDL_TLSID slot;
slouken@7391
   223
            tls_being_created = SDL_TRUE;
slouken@7393
   224
            slot = SDL_TLSCreate();
slouken@7391
   225
            tls_being_created = SDL_FALSE;
slouken@7393
   226
            SDL_MemoryBarrierRelease();
slouken@7393
   227
            tls_errbuf = slot;
slouken@7391
   228
        }
slouken@7393
   229
        SDL_AtomicUnlock(&tls_lock);
slouken@7391
   230
    }
slouken@7391
   231
    if (!tls_errbuf) {
slouken@7391
   232
        return &SDL_global_errbuf;
slouken@7391
   233
    }
slouken@0
   234
slouken@7393
   235
    SDL_MemoryBarrierAcquire();
slouken@7393
   236
    errbuf = (SDL_error *)SDL_TLSGet(tls_errbuf);
slouken@7393
   237
    if (errbuf == ALLOCATION_IN_PROGRESS) {
slouken@7393
   238
        return &SDL_global_errbuf;
slouken@7393
   239
    }
slouken@7391
   240
    if (!errbuf) {
slouken@7393
   241
        /* Mark that we're in the middle of allocating our buffer */
slouken@7393
   242
        SDL_TLSSet(tls_errbuf, ALLOCATION_IN_PROGRESS, NULL);
slouken@7391
   243
        errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
slouken@7391
   244
        if (!errbuf) {
slouken@7393
   245
            SDL_TLSSet(tls_errbuf, NULL, NULL);
slouken@7391
   246
            return &SDL_global_errbuf;
slouken@1895
   247
        }
slouken@7391
   248
        SDL_zerop(errbuf);
slouken@7393
   249
        SDL_TLSSet(tls_errbuf, errbuf, SDL_free);
slouken@1895
   250
    }
slouken@7391
   251
    return errbuf;
slouken@0
   252
}
slouken@0
   253
slouken@0
   254
slouken@0
   255
/* Arguments and callback to setup and run the user thread function */
slouken@1895
   256
typedef struct
slouken@1895
   257
{
slouken@1895
   258
    int (SDLCALL * func) (void *);
slouken@1895
   259
    void *data;
slouken@1895
   260
    SDL_Thread *info;
slouken@1895
   261
    SDL_sem *wait;
slouken@0
   262
} thread_args;
slouken@0
   263
slouken@1895
   264
void
slouken@1895
   265
SDL_RunThread(void *data)
slouken@0
   266
{
icculus@5969
   267
    thread_args *args = (thread_args *) data;
icculus@5969
   268
    int (SDLCALL * userfunc) (void *) = args->func;
icculus@5969
   269
    void *userdata = args->data;
icculus@7978
   270
    SDL_Thread *thread = args->info;
icculus@7978
   271
    int *statusloc = &thread->status;
slouken@0
   272
slouken@7393
   273
    /* Perform any system-dependent setup - this function may not fail */
icculus@7978
   274
    SDL_SYS_SetupThread(thread->name);
slouken@0
   275
slouken@1895
   276
    /* Get the thread id */
icculus@7978
   277
    thread->threadid = SDL_ThreadID();
slouken@0
   278
slouken@1895
   279
    /* Wake up the parent thread */
slouken@1895
   280
    SDL_SemPost(args->wait);
slouken@0
   281
slouken@1895
   282
    /* Run the function */
slouken@1895
   283
    *statusloc = userfunc(userdata);
slouken@7393
   284
slouken@7393
   285
    /* Clean up thread-local storage */
slouken@7393
   286
    SDL_TLSCleanup();
icculus@7978
   287
icculus@7978
   288
    /* Mark us as ready to be joined (or detached) */
icculus@7978
   289
    if (!SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_ZOMBIE)) {
icculus@7978
   290
        /* Clean up if something already detached us. */
icculus@7978
   291
        if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_DETACHED, SDL_THREAD_STATE_CLEANED)) {
icculus@7978
   292
            if (thread->name) {
icculus@7978
   293
                SDL_free(thread->name);
icculus@7978
   294
            }
icculus@7978
   295
            SDL_free(thread);
icculus@7978
   296
        }
icculus@7978
   297
    }
slouken@0
   298
}
slouken@0
   299
icculus@8094
   300
#ifdef SDL_CreateThread
icculus@8094
   301
#undef SDL_CreateThread
icculus@8094
   302
#endif
icculus@8094
   303
#if SDL_DYNAMIC_API
icculus@8094
   304
#define SDL_CreateThread SDL_CreateThread_REAL
icculus@8094
   305
#endif
icculus@8094
   306
slouken@1471
   307
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
icculus@10145
   308
static SDL_Thread *
icculus@10145
   309
SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
icculus@10145
   310
                 const char *name, const size_t stacksize, void *data,
slouken@1895
   311
                 pfnSDL_CurrentBeginThread pfnBeginThread,
slouken@1895
   312
                 pfnSDL_CurrentEndThread pfnEndThread)
icculus@1190
   313
#else
icculus@10145
   314
static SDL_Thread *
icculus@10145
   315
SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
icculus@10145
   316
                const char *name, const size_t stacksize, void *data)
icculus@1190
   317
#endif
slouken@0
   318
{
slouken@1895
   319
    SDL_Thread *thread;
slouken@1895
   320
    thread_args *args;
slouken@1895
   321
    int ret;
slouken@0
   322
slouken@1895
   323
    /* Allocate memory for the thread info structure */
slouken@1895
   324
    thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
slouken@1895
   325
    if (thread == NULL) {
slouken@1895
   326
        SDL_OutOfMemory();
slouken@1895
   327
        return (NULL);
slouken@1895
   328
    }
icculus@7978
   329
    SDL_zerop(thread);
slouken@1895
   330
    thread->status = -1;
icculus@7978
   331
    SDL_AtomicSet(&thread->state, SDL_THREAD_STATE_ALIVE);
slouken@0
   332
slouken@1895
   333
    /* Set up the arguments for the thread */
icculus@5969
   334
    if (name != NULL) {
icculus@5969
   335
        thread->name = SDL_strdup(name);
icculus@5969
   336
        if (thread->name == NULL) {
icculus@5969
   337
            SDL_OutOfMemory();
icculus@5969
   338
            SDL_free(thread);
icculus@5969
   339
            return (NULL);
icculus@5969
   340
        }
icculus@5969
   341
    }
icculus@5969
   342
icculus@5969
   343
    /* Set up the arguments for the thread */
slouken@1895
   344
    args = (thread_args *) SDL_malloc(sizeof(*args));
slouken@1895
   345
    if (args == NULL) {
slouken@1895
   346
        SDL_OutOfMemory();
slouken@7606
   347
        if (thread->name) {
slouken@7606
   348
            SDL_free(thread->name);
slouken@7606
   349
        }
slouken@1895
   350
        SDL_free(thread);
slouken@1895
   351
        return (NULL);
slouken@1895
   352
    }
slouken@1895
   353
    args->func = fn;
slouken@1895
   354
    args->data = data;
slouken@1895
   355
    args->info = thread;
slouken@1895
   356
    args->wait = SDL_CreateSemaphore(0);
slouken@1895
   357
    if (args->wait == NULL) {
slouken@7606
   358
        if (thread->name) {
slouken@7606
   359
            SDL_free(thread->name);
slouken@7606
   360
        }
slouken@1895
   361
        SDL_free(thread);
slouken@1895
   362
        SDL_free(args);
slouken@1895
   363
        return (NULL);
slouken@1895
   364
    }
slouken@0
   365
icculus@10145
   366
    thread->stacksize = stacksize;
icculus@10145
   367
slouken@1895
   368
    /* Create the thread and go! */
slouken@1471
   369
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
slouken@1895
   370
    ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
icculus@1190
   371
#else
slouken@1895
   372
    ret = SDL_SYS_CreateThread(thread, args);
icculus@1190
   373
#endif
slouken@1895
   374
    if (ret >= 0) {
slouken@1895
   375
        /* Wait for the thread function to use arguments */
slouken@1895
   376
        SDL_SemWait(args->wait);
slouken@1895
   377
    } else {
slouken@1895
   378
        /* Oops, failed.  Gotta free everything */
slouken@7606
   379
        if (thread->name) {
slouken@7606
   380
            SDL_free(thread->name);
slouken@7606
   381
        }
slouken@1895
   382
        SDL_free(thread);
slouken@1895
   383
        thread = NULL;
slouken@1895
   384
    }
slouken@1895
   385
    SDL_DestroySemaphore(args->wait);
slouken@1895
   386
    SDL_free(args);
slouken@0
   387
slouken@1895
   388
    /* Everything is running now */
slouken@1895
   389
    return (thread);
slouken@0
   390
}
slouken@0
   391
icculus@10145
   392
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
icculus@10145
   393
DECLSPEC SDL_Thread *SDLCALL
icculus@10145
   394
SDL_CreateThread(int (SDLCALL * fn) (void *),
icculus@10145
   395
                 const char *name, void *data,
icculus@10145
   396
                 pfnSDL_CurrentBeginThread pfnBeginThread,
icculus@10145
   397
                 pfnSDL_CurrentEndThread pfnEndThread)
icculus@10145
   398
#else
icculus@10145
   399
DECLSPEC SDL_Thread *SDLCALL
icculus@10145
   400
SDL_CreateThread(int (SDLCALL * fn) (void *),
icculus@10145
   401
                 const char *name, void *data)
icculus@10145
   402
#endif
icculus@10145
   403
{
icculus@10145
   404
    /* !!! FIXME: in 2.1, just make stackhint part of the usual API. */
icculus@10145
   405
    const char *stackhint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE);
icculus@10145
   406
    size_t stacksize = 0;
icculus@10145
   407
icculus@10145
   408
    /* If the SDL_HINT_THREAD_STACK_SIZE exists, use it */
icculus@10145
   409
    if (stackhint != NULL) {
icculus@10145
   410
        char *endp = NULL;
icculus@10145
   411
        const Sint64 hintval = SDL_strtoll(stackhint, &endp, 10);
icculus@10145
   412
        if ((*stackhint != '\0') && (*endp == '\0')) {  /* a valid number? */
icculus@10145
   413
            if (hintval > 0) {  /* reject bogus values. */
icculus@10145
   414
                stacksize = (size_t) hintval;
icculus@10145
   415
            }
icculus@10145
   416
        }
icculus@10145
   417
    }
icculus@10145
   418
icculus@10145
   419
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
icculus@10145
   420
    return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, pfnBeginThread, pfnEndThread);
icculus@10145
   421
#else
icculus@10145
   422
    return SDL_CreateThreadWithStackSize(fn, name, stacksize, data);
icculus@10145
   423
#endif
icculus@10145
   424
}
icculus@10145
   425
icculus@10146
   426
SDL_Thread *
icculus@10146
   427
SDL_CreateThreadInternal(int (SDLCALL * fn) (void *), const char *name,
icculus@10146
   428
                         const size_t stacksize, void *data) {
icculus@10146
   429
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
icculus@10146
   430
    return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, NULL, NULL);
icculus@10146
   431
#else
icculus@10146
   432
    return SDL_CreateThreadWithStackSize(fn, name, stacksize, data);
icculus@10146
   433
#endif
icculus@10146
   434
}
icculus@10146
   435
slouken@5506
   436
SDL_threadID
slouken@5506
   437
SDL_GetThreadID(SDL_Thread * thread)
slouken@5506
   438
{
slouken@5506
   439
    SDL_threadID id;
slouken@5506
   440
slouken@5506
   441
    if (thread) {
slouken@5506
   442
        id = thread->threadid;
slouken@5506
   443
    } else {
slouken@5506
   444
        id = SDL_ThreadID();
slouken@5506
   445
    }
slouken@5506
   446
    return id;
slouken@5506
   447
}
slouken@5506
   448
icculus@5969
   449
const char *
icculus@5969
   450
SDL_GetThreadName(SDL_Thread * thread)
icculus@5969
   451
{
slouken@7606
   452
    if (thread) {
slouken@7606
   453
        return thread->name;
slouken@7606
   454
    } else {
slouken@7606
   455
        return NULL;
slouken@7606
   456
    }
icculus@5969
   457
}
icculus@5969
   458
slouken@5506
   459
int
slouken@5509
   460
SDL_SetThreadPriority(SDL_ThreadPriority priority)
slouken@5506
   461
{
slouken@5509
   462
    return SDL_SYS_SetThreadPriority(priority);
slouken@5506
   463
}
slouken@5506
   464
slouken@1895
   465
void
slouken@1895
   466
SDL_WaitThread(SDL_Thread * thread, int *status)
slouken@0
   467
{
slouken@1895
   468
    if (thread) {
slouken@1895
   469
        SDL_SYS_WaitThread(thread);
slouken@1895
   470
        if (status) {
slouken@1895
   471
            *status = thread->status;
slouken@1895
   472
        }
slouken@7606
   473
        if (thread->name) {
slouken@7606
   474
            SDL_free(thread->name);
slouken@7606
   475
        }
slouken@1895
   476
        SDL_free(thread);
slouken@1895
   477
    }
slouken@0
   478
}
slouken@0
   479
icculus@7978
   480
void
icculus@7978
   481
SDL_DetachThread(SDL_Thread * thread)
icculus@7978
   482
{
icculus@7978
   483
    if (!thread) {
icculus@7978
   484
        return;
icculus@7978
   485
    }
icculus@7978
   486
icculus@7978
   487
    /* Grab dibs if the state is alive+joinable. */
icculus@7978
   488
    if (SDL_AtomicCAS(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_DETACHED)) {
icculus@7978
   489
        SDL_SYS_DetachThread(thread);
icculus@7978
   490
    } else {
icculus@7978
   491
        /* all other states are pretty final, see where we landed. */
slouken@8922
   492
        const int thread_state = SDL_AtomicGet(&thread->state);
slouken@8922
   493
        if ((thread_state == SDL_THREAD_STATE_DETACHED) || (thread_state == SDL_THREAD_STATE_CLEANED)) {
icculus@7978
   494
            return;  /* already detached (you shouldn't call this twice!) */
slouken@8922
   495
        } else if (thread_state == SDL_THREAD_STATE_ZOMBIE) {
icculus@7978
   496
            SDL_WaitThread(thread, NULL);  /* already done, clean it up. */
icculus@7978
   497
        } else {
icculus@7978
   498
            SDL_assert(0 && "Unexpected thread state");
icculus@7978
   499
        }
icculus@7978
   500
    }
icculus@7978
   501
}
icculus@7978
   502
slouken@1895
   503
/* vi: set ts=4 sw=4 expandtab: */