var.hpp (7840B)
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_VAR_HPP 11 #define RL_VAR_HPP 12 #ifdef _MSC_VER 13 # pragma once 14 #endif 15 16 #include "base.hpp" 17 #include "context.hpp" 18 #include "signature.hpp" 19 #include "atomic_events.hpp" 20 21 22 namespace rl 23 { 24 25 template<typename T> 26 class var; 27 28 29 30 template<typename T> 31 class var_proxy_const 32 { 33 public: 34 var_proxy_const(var<T> const& v, debug_info_param info) 35 : var_(const_cast<var<T>&>(v)) 36 , info_(info) 37 { 38 } 39 40 T load() const 41 { 42 return var_.load(info_); 43 } 44 45 operator T () const 46 { 47 return this->load(); 48 } 49 50 T const operator -> () const 51 { 52 return this->load(); 53 } 54 55 protected: 56 var<T>& var_; 57 debug_info info_; 58 59 private: 60 var_proxy_const& operator = (var_proxy_const const&); 61 }; 62 63 64 65 66 template<typename T> 67 class var_proxy : public var_proxy_const<T> 68 { 69 public: 70 typedef typename atomic_add_type<T>::type add_type; 71 72 var_proxy(var<T>& v, debug_info_param info) 73 : var_proxy_const<T>(v, info) 74 { 75 } 76 77 void store(T value) 78 { 79 this->var_.store(value, this->info_); 80 } 81 82 template<typename Y> 83 T operator = (var_proxy_const<Y> const& v) 84 { 85 Y y = v.load(); 86 T t = y; 87 store(t); 88 return t; 89 } 90 91 T operator = (var_proxy<T> const& v) 92 { 93 T t = v.load(); 94 store(t); 95 return t; 96 } 97 98 T operator = (T value) 99 { 100 store(value); 101 return value; 102 } 103 104 T operator -> () 105 { 106 return this->load(); 107 } 108 109 T operator ++ (int) 110 { 111 T v = this->load(); 112 T y = ++v; 113 this->store(y); 114 return v; 115 } 116 117 T operator -- (int) 118 { 119 T v = this->load(); 120 T y = --v; 121 this->store(y); 122 return v; 123 } 124 125 T operator ++ () 126 { 127 T v = this->load(); 128 this->store(++v); 129 return v; 130 } 131 132 T operator -- () 133 { 134 T v = this->load(); 135 this->store(--v); 136 return v; 137 } 138 139 T operator += (add_type value) 140 { 141 T v = this->load(); 142 v += value; 143 this->store(v); 144 return v; 145 } 146 147 T operator -= (add_type value) 148 { 149 T v = this->load(); 150 v -= value; 151 this->store(v); 152 return v; 153 } 154 155 T operator &= (T value) 156 { 157 T v = this->load(); 158 v &= value; 159 this->store(v); 160 return v; 161 } 162 163 T operator |= (T value) 164 { 165 T v = this->load(); 166 v |= value; 167 this->store(v); 168 return v; 169 } 170 171 T operator ^= (T value) 172 { 173 T v = this->load(); 174 v ^= value; 175 this->store(v); 176 return v; 177 } 178 }; 179 180 181 182 183 template<typename T> 184 struct var_event 185 { 186 debug_info var_info_; 187 var<T> const* var_addr_; 188 T value_; 189 bool load_; 190 191 template<typename Y> 192 struct map_type 193 { 194 typedef T result; 195 }; 196 197 template<typename Y> 198 struct map_type<Y*> 199 { 200 typedef void* result; 201 }; 202 203 void output(std::ostream& s) const 204 { 205 s << "<" << std::hex << var_addr_ << std::dec << "> " 206 << (load_ ? "load" : "store") << ", value=" << (typename map_type<T>::result)value_; 207 } 208 }; 209 210 211 212 213 template<typename T> 214 class var 215 { 216 public: 217 var() 218 { 219 value_ = 0; 220 initialized_ = false; 221 data_ = ctx().var_ctor(); 222 } 223 224 var(T value) 225 { 226 init(value); 227 } 228 229 var(var const& r) 230 { 231 init(r.load($)); 232 } 233 234 ~var() 235 { 236 sign_.check($); 237 ctx().var_dtor(data_); 238 } 239 240 var_proxy_const<T> operator () (debug_info_param info) const 241 { 242 return var_proxy_const<T>(*this, info); 243 } 244 245 var_proxy<T> operator () (debug_info_param info) 246 { 247 return var_proxy<T>(*this, info); 248 } 249 250 private: 251 T value_; 252 bool initialized_; 253 254 var_data* data_; 255 256 signature<123456789> sign_; 257 friend class var_proxy<T>; 258 friend class var_proxy_const<T>; 259 260 void init(T value) 261 { 262 context& c = ctx(); 263 initialized_ = true; 264 value_ = value; 265 data_ = ctx().var_ctor(); 266 data_->init(*c.threadx_); 267 } 268 269 T load(debug_info_param info) const 270 { 271 context& c = ctx(); 272 sign_.check(info); 273 274 if (false == initialized_) 275 { 276 RL_HIST(var_event<T>) {RL_INFO, this, T(), true} RL_HIST_END(); 277 RL_ASSERT_IMPL(false, test_result_unitialized_access, "", info); 278 } 279 280 if (false == c.invariant_executing) 281 { 282 if (false == data_->load(*c.threadx_)) 283 { 284 RL_HIST(var_event<T>) {RL_INFO, this, T(), true} RL_HIST_END(); 285 RL_ASSERT_IMPL(false, test_result_data_race, "data race detected", info); 286 } 287 288 T const v = value_; 289 290 RL_HIST(var_event<T>) {RL_INFO, this, v, true} RL_HIST_END(); 291 292 return v; 293 } 294 else 295 { 296 return value_; 297 } 298 } 299 300 void store(T v, debug_info_param info) 301 { 302 context& c = ctx(); 303 RL_VERIFY(false == c.invariant_executing); 304 sign_.check(info); 305 306 if (initialized_) 307 { 308 if (false == data_->store(*c.threadx_)) 309 { 310 RL_HIST(var_event<T>) {RL_INFO, this, T(), false} RL_HIST_END(); 311 RL_ASSERT_IMPL(false, test_result_data_race, "data race detected", info); 312 } 313 } 314 else 315 { 316 initialized_ = true; 317 data_->init(*c.threadx_); 318 } 319 320 value_ = v; 321 322 RL_HIST(var_event<T>) {RL_INFO, this, v, false} RL_HIST_END(); 323 } 324 325 var& operator = (var const& r); 326 }; 327 328 329 330 331 template<thread_id_t thread_count> 332 struct var_data_impl : var_data 333 { 334 typedef thread_info<thread_count> thread_info_t; 335 336 timestamp_t load_acq_rel_timestamp_ [thread_count]; 337 timestamp_t store_acq_rel_timestamp_ [thread_count]; 338 339 var_data_impl() 340 { 341 foreach<thread_count>(load_acq_rel_timestamp_, assign_zero); 342 foreach<thread_count>(store_acq_rel_timestamp_, assign_zero); 343 } 344 345 virtual void init(thread_info_base& th) 346 { 347 th.own_acq_rel_order_ += 1; 348 store_acq_rel_timestamp_[th.index_] = th.own_acq_rel_order_; 349 } 350 351 virtual bool store(thread_info_base& th) 352 { 353 for (thread_id_t i = 0; i != thread_count; ++i) 354 { 355 if (th.acq_rel_order_[i] < store_acq_rel_timestamp_[i]) 356 return false; 357 if (th.acq_rel_order_[i] < load_acq_rel_timestamp_[i]) 358 return false; 359 } 360 361 th.own_acq_rel_order_ += 1; 362 store_acq_rel_timestamp_[th.index_] = th.own_acq_rel_order_; 363 return true; 364 } 365 366 virtual bool load(thread_info_base& th) 367 { 368 for (thread_id_t i = 0; i != thread_count; ++i) 369 { 370 if (th.acq_rel_order_[i] < store_acq_rel_timestamp_[i]) 371 return false; 372 } 373 374 th.own_acq_rel_order_ += 1; 375 load_acq_rel_timestamp_[th.index_] = th.own_acq_rel_order_; 376 return true; 377 } 378 379 virtual ~var_data_impl() {} // just to calm down gcc 380 }; 381 382 383 384 } 385 386 387 388 #endif