medfall

A super great game engine
Log | Files | Refs

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