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