medfall

A super great game engine
Log | Files | Refs

thread_local.hpp (4296B)


      1 /*  Relacy Race Detector
      2  *  Copyright (c) 2008-2013, Dmitry S. Vyukov
      3  *  All rights reserved.
      4  *  This software is provided AS-IS with no warranty, either express or implied.
      5  *  This software is distributed under a license and may not be copied,
      6  *  modified or distributed except as expressly authorized under the
      7  *  terms of the license contained in the file LICENSE in this distribution.
      8  */
      9 
     10 #ifndef RL_THREAD_LOCAL_HPP
     11 #define RL_THREAD_LOCAL_HPP
     12 #ifdef _MSC_VER
     13 #   pragma once
     14 #endif
     15 
     16 #include "base.hpp"
     17 #include "signature.hpp"
     18 #include "context.hpp"
     19 
     20 
     21 namespace rl
     22 {
     23 
     24 
     25 class generic_thread_local : nocopy<>
     26 {
     27 public:
     28     generic_thread_local()
     29         : index_(-1)
     30     {
     31     }
     32 
     33     ~generic_thread_local()
     34     {
     35     }
     36 
     37     void init(void (*dtor)(intptr_t), debug_info_param info)
     38     {
     39         sign_.check(info);
     40         //RL_ASSERT(index_ == -1);
     41         index_ = ctx().thread_local_alloc(dtor);
     42     }
     43 
     44     void deinit(debug_info_param info)
     45     {
     46         sign_.check(info);
     47         RL_ASSERT(index_ != -1);
     48         ctx().thread_local_free(index_);
     49         index_ = -1;
     50     }
     51 
     52     void set(intptr_t value, debug_info_param info)
     53     {
     54         sign_.check(info);
     55         ctx().thread_local_set(index_, value);
     56     }
     57 
     58     intptr_t get(debug_info_param info)
     59     {
     60         sign_.check(info);
     61         return ctx().thread_local_get(index_);
     62     }
     63 
     64 private:
     65     signature<0xf1724ae2> sign_;
     66     int index_;
     67 };
     68 
     69 
     70 template<typename T>
     71 class thread_local_var;
     72 
     73 
     74 template<typename T>
     75 class thread_local_proxy
     76 {
     77 public:
     78     thread_local_proxy(thread_local_var<T>& var, debug_info_param info)
     79         : var_(var)
     80         , info_(info)
     81     {}
     82 
     83     operator T () const
     84     {
     85         return var_.get(info_);
     86     }
     87 
     88     T operator -> () const
     89     {
     90         return var_.get(info_);
     91     }
     92 
     93     thread_local_proxy operator = (T value)
     94     {
     95         var_.set(value, info_);
     96         return *this;
     97     }
     98 
     99 private:
    100     thread_local_var<T>& var_;
    101     debug_info info_;
    102     thread_local_proxy& operator = (thread_local_proxy const&);
    103 };
    104 
    105 
    106 template<typename T>
    107 class thread_local_var : generic_thread_local
    108 {
    109 public:
    110     thread_local_var()
    111         : ctx_seq_()
    112     {
    113     }
    114 
    115     ~thread_local_var()
    116     {
    117     }
    118 
    119     thread_local_proxy<T> operator () (debug_info_param info)
    120     {
    121         return thread_local_proxy<T>(*this, info);
    122     }
    123 
    124     void set(T value, debug_info_param info)
    125     {
    126         if (ctx_seq_ != ctx().get_ctx_seq())
    127         {
    128             ctx_seq_ = ctx().get_ctx_seq();
    129             generic_thread_local::init(0, info);
    130         }
    131         generic_thread_local::set((intptr_t)value, info);
    132     }
    133 
    134     T get(debug_info_param info)
    135     {
    136         if (ctx_seq_ != ctx().get_ctx_seq())
    137         {
    138             ctx_seq_ = ctx().get_ctx_seq();
    139             generic_thread_local::init(0, info);
    140         }
    141         return (T)generic_thread_local::get(info);
    142     }
    143 
    144 private:
    145     unsigned ctx_seq_;
    146 };
    147 
    148 
    149 inline unsigned long rl_TlsAlloc(debug_info_param info)
    150 {
    151 #ifndef RL_GC
    152     //!!! may break on x64 platform
    153     // TLS index is exactly DWORD (not DWORD_PTR), so one has to use indirection
    154     return (unsigned long)new (info) thread_local_var<void*> ();
    155 #else
    156     void* p = ctx().alloc(sizeof(thread_local_var<void*>), false, info);
    157     new (p) thread_local_var<void*> ();
    158     return (unsigned long)p;
    159 #endif
    160 }
    161 
    162 inline void rl_TlsFree(unsigned long slot, debug_info_param info)
    163 {
    164 #ifndef RL_GC
    165     delete_impl((thread_local_var<void*>*)slot, info);
    166 #else
    167     thread_local_var<void*>* t = (thread_local_var<void*>*)slot;
    168     t->~thread_local_var<void*>();
    169     ctx().free(t, false, info);
    170 #endif
    171 }
    172 
    173 inline void* rl_TlsGetValue(unsigned long slot, debug_info_param info)
    174 {
    175     return ((thread_local_var<void*>*)slot)->get(info);
    176 }
    177 
    178 inline int rl_TlsSetValue(unsigned long slot, void* value, debug_info_param info)
    179 {
    180     ((thread_local_var<void*>*)slot)->set(value, info);
    181     return 1;
    182 }
    183 
    184 
    185 #define TlsAlloc() rl::rl_TlsAlloc($)
    186 #define TlsFree(slot) rl::rl_TlsFree((slot), $)
    187 #define TlsGetValue(slot) rl::rl_TlsGetValue((slot), $)
    188 #define TlsSetValue(slot, value) rl::rl_TlsSetValue((slot), (value), $)
    189 
    190 }
    191 
    192 #endif