src/thread/generic/SDL_systls.c
changeset 7393 358696c354a8
parent 7391 a29895dc5e9a
child 8093 b43765095a6f
equal deleted inserted replaced
7392:7e32fcb41b44 7393:358696c354a8
    18      misrepresented as being the original software.
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    20 */
    21 
    21 
    22 #include "SDL_config.h"
    22 #include "SDL_config.h"
    23 #include "SDL_thread.h"
    23 #include "../SDL_thread_c.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 
    24 
    51 
    25 
    52 static SDL_TLSData *GetTLSData()
    26 SDL_TLSData *
       
    27 SDL_SYS_GetTLSData()
    53 {
    28 {
    54     SDL_threadID thread = SDL_ThreadID();
    29     return SDL_Generic_GetTLSData();
    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 }
    30 }
   130 
    31 
   131 int
    32 int
   132 SDL_TLSSet(SDL_TLSID id, const void *value)
    33 SDL_SYS_SetTLSData(SDL_TLSData *data)
   133 {
    34 {
   134     SDL_TLSData *data;
    35     return SDL_Generic_SetTLSData(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 }
    36 }
   162 
    37 
   163 /* vi: set ts=4 sw=4 expandtab: */
    38 /* vi: set ts=4 sw=4 expandtab: */