src/thread/generic/SDL_systls.c
changeset 7391 a29895dc5e9a
child 7393 358696c354a8
equal deleted inserted replaced
7390:e4b98404baa4 7391:a29895dc5e9a
       
     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 
       
    22 #include "SDL_config.h"
       
    23 #include "SDL_thread.h"
       
    24 
       
    25 /* This is a generic implementation of thread-local storage which doesn't
       
    26    require additional OS support.
       
    27 
       
    28    It is not especially efficient and doesn't clean up thread-local storage
       
    29    as threads exit.  If there is a real OS that doesn't support thread-local
       
    30    storage this implementation should be improved to be production quality.
       
    31 */
       
    32 
       
    33 #define TLS_ALLOC_CHUNKSIZE 8
       
    34 
       
    35 typedef struct {
       
    36     int limit;
       
    37     void *data[1];
       
    38 } SDL_TLSData;
       
    39 
       
    40 typedef struct SDL_TLSEntry {
       
    41     SDL_threadID thread;
       
    42     SDL_TLSData *data;
       
    43     struct SDL_TLSEntry *next;
       
    44 } SDL_TLSEntry;
       
    45 
       
    46 static SDL_SpinLock tls_lock;
       
    47 static SDL_mutex *tls_mutex;
       
    48 static SDL_TLSEntry *thread_local_storage;
       
    49 static SDL_atomic_t tls_id;
       
    50 
       
    51 
       
    52 static SDL_TLSData *GetTLSData()
       
    53 {
       
    54     SDL_threadID thread = SDL_ThreadID();
       
    55     SDL_TLSEntry *entry;
       
    56     SDL_TLSData *data = NULL;
       
    57 
       
    58     if (!tls_mutex) {
       
    59         SDL_AtomicLock(&tls_lock);
       
    60         if (!tls_mutex) {
       
    61             tls_mutex = SDL_CreateMutex();
       
    62             if (!tls_mutex) {
       
    63                 SDL_AtomicUnlock(&tls_lock);
       
    64                 return NULL;
       
    65             }
       
    66         }
       
    67         SDL_AtomicUnlock(&tls_lock);
       
    68     }
       
    69 
       
    70     SDL_LockMutex(tls_mutex);
       
    71     for (entry = thread_local_storage; entry; entry = entry->next) {
       
    72         if (entry->thread == thread) {
       
    73             data = entry->data;
       
    74             break;
       
    75         }
       
    76     }
       
    77     SDL_UnlockMutex(tls_mutex);
       
    78 
       
    79     return data;
       
    80 }
       
    81 
       
    82 static int SetTLSData(SDL_TLSData *data)
       
    83 {
       
    84     SDL_threadID thread = SDL_ThreadID();
       
    85     SDL_TLSEntry *entry;
       
    86 
       
    87     /* GetTLSData() is always called first, so we can assume tls_mutex */
       
    88     SDL_LockMutex(tls_mutex);
       
    89     for (entry = thread_local_storage; entry; entry = entry->next) {
       
    90         if (entry->thread == thread) {
       
    91             entry->data = data;
       
    92             break;
       
    93         }
       
    94     }
       
    95     if (!entry) {
       
    96         entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
       
    97         if (entry) {
       
    98             entry->thread = thread;
       
    99             entry->data = data;
       
   100             entry->next = thread_local_storage;
       
   101             thread_local_storage = entry;
       
   102         }
       
   103     }
       
   104     SDL_UnlockMutex(tls_mutex);
       
   105 
       
   106     if (!entry) {
       
   107         return SDL_OutOfMemory();
       
   108     }
       
   109     return 0;
       
   110 }
       
   111 
       
   112 
       
   113 SDL_TLSID
       
   114 SDL_TLSCreate()
       
   115 {
       
   116     return SDL_AtomicIncRef(&tls_id)+1;
       
   117 }
       
   118 
       
   119 void *
       
   120 SDL_TLSGet(SDL_TLSID id)
       
   121 {
       
   122     SDL_TLSData *data;
       
   123 
       
   124     data = GetTLSData();
       
   125     if (!data || id <= 0 || id > data->limit) {
       
   126         return NULL;
       
   127     }
       
   128     return data->data[id-1];
       
   129 }
       
   130 
       
   131 int
       
   132 SDL_TLSSet(SDL_TLSID id, const void *value)
       
   133 {
       
   134     SDL_TLSData *data;
       
   135 
       
   136     if (id <= 0) {
       
   137         return SDL_InvalidParamError(id);
       
   138     }
       
   139 
       
   140     data = GetTLSData();
       
   141     if (!data || id > data->limit) {
       
   142         int i, oldlimit, newlimit;
       
   143 
       
   144         oldlimit = data ? data->limit : 0;
       
   145         newlimit = (id + TLS_ALLOC_CHUNKSIZE);
       
   146         data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
       
   147         if (!data) {
       
   148             return SDL_OutOfMemory();
       
   149         }
       
   150         data->limit = newlimit;
       
   151         for (i = oldlimit; i < newlimit; ++i) {
       
   152             data->data[i] = NULL;
       
   153         }
       
   154         if (SetTLSData(data) != 0) {
       
   155             return -1;
       
   156         }
       
   157     }
       
   158 
       
   159     data->data[id-1] = SDL_const_cast(void*, value);
       
   160     return 0;
       
   161 }
       
   162 
       
   163 /* vi: set ts=4 sw=4 expandtab: */