medfall

A super great game engine
Log | Files | Refs

context_base.hpp (8697B)


      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_CONTEXT_BASE_HPP
     11 #define RL_CONTEXT_BASE_HPP
     12 #ifdef _MSC_VER
     13 #   pragma once
     14 #endif
     15 
     16 #include "base.hpp"
     17 #include "history.hpp"
     18 #include "memory.hpp"
     19 #include "test_result.hpp"
     20 #include "slab_allocator.hpp"
     21 #include "test_params.hpp"
     22 #include "random.hpp"
     23 #include "foreach.hpp"
     24 #include "thread_base.hpp"
     25 #include "context_addr_hash.hpp"
     26 
     27 
     28 #ifdef RL_DEBUGBREAK_ON_ASSERT
     29 #    ifdef _MSC_VER
     30 #        define RL_DEBUGBREAK_ON_ASSERT_IMPL {if (IsDebuggerPresent()) __debugbreak();}
     31 #    else
     32 #        define RL_DEBUGBREAK_ON_ASSERT_IMPL {__asm("int3");}
     33 #    endif
     34 #else
     35 #   define RL_DEBUGBREAK_ON_ASSERT_IMPL
     36 #endif
     37 
     38 #ifdef RL_DEBUGBREAK_ON_FAILURE
     39 #    ifdef _MSC_VER
     40 #        define RL_DEBUGBREAK_ON_FAILURE_IMPL {if (IsDebuggerPresent()) __debugbreak();}
     41 #    else
     42 #        define RL_DEBUGBREAK_ON_FAILURE_IMPL {__asm("int3");}
     43 #    endif
     44 #else
     45 #   define RL_DEBUGBREAK_ON_FAILURE_IMPL
     46 #endif
     47 
     48 
     49 
     50 namespace rl
     51 {
     52 
     53 class thread_info_base;
     54 
     55 struct atomic_data {};
     56 struct var_data
     57 {
     58     virtual void init(thread_info_base& th) = 0;
     59     virtual bool store(thread_info_base& th) = 0;
     60     virtual bool load(thread_info_base& th) = 0;
     61     virtual ~var_data() {} // just to calm down gcc
     62 };
     63 
     64 struct generic_mutex_data;
     65 struct condvar_data;
     66 struct sema_data;
     67 struct event_data;
     68 
     69 
     70 struct user_msg_event
     71 {
     72     string msg_;
     73 
     74     void output(std::ostream& s) const
     75     {
     76         s << msg_;
     77     }            
     78 };
     79 
     80 class context;
     81 
     82 template<int fake = 0>
     83 struct context_holder
     84 {
     85     static context* instance_;
     86 
     87     static long volatile ctx_seq;
     88 };
     89 
     90 template<int fake>
     91 long volatile context_holder<fake>::ctx_seq = 0;
     92 
     93 class context
     94     : public thread_local_context_iface
     95     , public context_addr_hash_iface
     96     , nocopy<>
     97 {
     98 public:
     99     static context& instance()
    100     {
    101         //!!! disabled for check in operator new RL_VERIFY(context_holder<>::instance_);
    102         return *context_holder<>::instance_;
    103     }
    104 
    105     virtual atomic_data* atomic_ctor(void* ctx) = 0;
    106     virtual void atomic_dtor(atomic_data* data) = 0;
    107 
    108     virtual var_data* var_ctor() = 0;
    109     virtual void var_dtor(var_data* data) = 0;
    110 
    111     virtual generic_mutex_data* mutex_ctor(bool is_rw, bool is_exclusive_recursive, bool is_shared_recursive, bool failing_try_lock) = 0;
    112     virtual void mutex_dtor(generic_mutex_data* m) = 0;
    113 
    114     virtual condvar_data* condvar_ctor(bool allow_spurious_wakeups) = 0;
    115     virtual void condvar_dtor(condvar_data* cv) = 0;
    116 
    117     virtual sema_data* sema_ctor(bool spurious_wakeups, unsigned initial_count, unsigned max_count) = 0;
    118     virtual void sema_dtor(sema_data* cv) = 0;
    119 
    120     virtual event_data* event_ctor(bool manual_reset, bool initial_state) = 0;
    121     virtual void event_dtor(event_data* cv) = 0;
    122 
    123     virtual void rl_global_fence() = 0;
    124     virtual void sched() = 0;
    125     virtual void yield(unsigned count, debug_info_param info) = 0;
    126     virtual void fail_test(char const* desc, test_result_e res, debug_info_param info) = 0;
    127     virtual void rl_until(char const* desc, debug_info_param info) = 0;
    128 
    129     virtual void* alloc(size_t size, bool is_array, debug_info_param info) = 0;
    130 #ifdef RL_GC
    131     virtual void* alloc(size_t size, bool is_array, void(*dtor)(void*), debug_info_param info) = 0;
    132 #endif
    133     virtual void free(void* p, bool is_array, debug_info_param info) = 0;
    134 
    135     virtual void* alloc(size_t size) = 0;
    136     virtual void free(void* p) = 0;
    137     virtual size_t prev_alloc_size() = 0;
    138     virtual void set_debug_info(debug_info_param info) = 0;
    139 
    140     virtual void fiber_proc_impl(int thread_index) = 0;
    141 
    142     virtual unpark_reason park_current_thread(bool is_timed,
    143                                               bool allow_spurious_wakeup,
    144                                               bool do_switch,
    145                                               debug_info_param info) = 0;
    146     virtual void unpark_thread(thread_id_t th, bool do_switch, debug_info_param info) = 0;
    147     virtual void switch_back(debug_info_param info) = 0;
    148 
    149     virtual void atomic_thread_fence_acquire() = 0;
    150     virtual void atomic_thread_fence_release() = 0;
    151     virtual void atomic_thread_fence_acq_rel() = 0;
    152     virtual void atomic_thread_fence_seq_cst() = 0;
    153 
    154     virtual unsigned rand(unsigned limit, sched_type t) = 0;
    155 
    156     virtual win_waitable_object* create_thread(void*(*fn)(void*), void* ctx) = 0;
    157 
    158     virtual unpark_reason wfmo_park(void** ws,
    159                                     win_waitable_object** wo,
    160                                     size_t count,
    161                                     bool wait_all,
    162                                     bool is_timed,
    163                                     debug_info_param info) = 0;
    164 	
    165     int get_errno();
    166     void set_errno(int value);
    167 
    168     thread_info_base* threadx_;
    169     timestamp_t* seq_cst_fence_order_;
    170 
    171     bool invariant_executing;
    172 
    173     RL_INLINE bool collecting_history() const
    174     {
    175         return params_.collect_history && false == invariant_executing;
    176     }
    177 
    178     template<typename event_t>
    179     void exec_log(debug_info_param info, event_t const& ev);
    180 
    181     void exec_log_msg(debug_info_param info, char const* msg)
    182     {
    183         user_msg_event ev = {msg};
    184         exec_log(info, ev);
    185     }
    186 
    187     bool is_random_sched() const
    188     {
    189         return is_random_sched_;
    190     }
    191 
    192     unsigned get_ctx_seq() const
    193     {
    194         return ctx_seq_;
    195     }
    196 
    197     void disable_preemption();
    198     void enable_preemption();
    199 
    200     virtual thread_id_t get_thread_count() const = 0;
    201 
    202     thread_id_t current_thread() const
    203     {
    204         return threadx_->index_;
    205     }
    206 
    207     void iteration_begin()
    208     {
    209     }
    210 
    211 protected:
    212     history_mgr history_;
    213     test_params& params_;
    214     unsigned disable_preemption_;
    215     int                         disable_alloc_;
    216 
    217     context(thread_id_t thread_count, test_params& params)
    218         : history_(*params.output_stream, thread_count)
    219         , params_(params)
    220         , disable_alloc_(1)
    221     {
    222         RL_VERIFY(0 == context_holder<>::instance_);
    223         context_holder<>::instance_ = this;
    224 
    225         is_random_sched_ = params_.search_type == random_scheduler_type;
    226 
    227 #ifdef _MSC_VER
    228         ctx_seq_ = _InterlockedExchangeAdd(&context_holder<>::ctx_seq, 1) + 1;
    229 #else
    230         ctx_seq_ = __sync_fetch_and_add(&context_holder<>::ctx_seq, 1) + 1;
    231 #endif
    232     }
    233 
    234     virtual ~context()
    235     {
    236         RL_VERIFY(this == context_holder<>::instance_);
    237         context_holder<>::instance_ = 0;
    238     }
    239     
    240 private:
    241     bool is_random_sched_;
    242     unsigned ctx_seq_;
    243 };
    244 
    245 
    246 template<int fake>
    247 context* context_holder<fake>::instance_ = 0;
    248 
    249 
    250 
    251 
    252 inline context& ctx()
    253 {
    254     return context::instance();
    255 }
    256 
    257 
    258 inline int get_errno()
    259 {
    260     return ctx().get_errno();
    261 }
    262 
    263 inline void set_errno(int value)
    264 {
    265     return ctx().set_errno(value);
    266 }
    267 
    268 class preemption_disabler : nocopy<>
    269 {
    270 public:
    271     preemption_disabler(context& c)
    272         : c_(c)
    273     {
    274         c_.disable_preemption();
    275     }
    276 
    277     ~preemption_disabler()
    278     {
    279         c_.enable_preemption();
    280     }
    281 
    282 private:
    283     context& c_;
    284 };
    285 
    286 
    287 }
    288 
    289 
    290 #define RL_HIST_IMPL(C, INFO, TYPE) \
    291     do { \
    292         if (C.collecting_history()) { \
    293             rl::debug_info const& rl_info_c = INFO; \
    294             rl::context& rl_hist_c = C; \
    295             TYPE ev = \
    296 /**/
    297 
    298 #define RL_HIST_END() \
    299                         ; \
    300             rl_hist_c.exec_log(rl_info_c, ev); \
    301         } \
    302     } while ((void)0, 0) \
    303 /**/
    304 
    305 #define RL_HIST_CTX(TYPE) RL_HIST_IMPL((*this), info, TYPE)
    306 
    307 #define RL_HIST(TYPE) RL_HIST_IMPL(c, info, TYPE)
    308 
    309 #define RL_LOG(desc) rl::ctx().exec_log_msg(RL_INFO, desc)
    310 
    311 
    312 
    313 #ifdef _MSC_VER
    314 #   define RL_ASSERT_IMPL(x, res, str, info) do {if (!((void)0, (x))) {{RL_DEBUGBREAK_ON_ASSERT_IMPL} rl::ctx().fail_test(str, res, info);}} while ((void)0, 0)
    315 #else
    316 #   define RL_ASSERT_IMPL(x, res, str, info) do {if (!((void)0, (x))) rl::ctx().fail_test(str, res, info);} while ((void)0, 0)
    317 #endif
    318 #define RL_ASSERT(x) RL_ASSERT_IMPL(x, rl::test_result_user_assert_failed, "assertion: " #x, RL_INFO)
    319 #define RL_UNTIL(x) do {if ((x)) rl::ctx().rl_until(#x, RL_INFO);} while ((void)0, 0)
    320 
    321 
    322 #endif