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