event.hpp (9754B)
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_EVENT_HPP 11 #define RL_EVENT_HPP 12 #ifdef _MSC_VER 13 # pragma once 14 #endif 15 16 #include "../base.hpp" 17 #include "../context_base.hpp" 18 #include "../sync_var.hpp" 19 #include "../waitset.hpp" 20 #include "semaphore.hpp" 21 22 23 namespace rl 24 { 25 26 27 struct event_data 28 { 29 virtual void set(debug_info_param info) = 0; 30 virtual void reset(debug_info_param info) = 0; 31 virtual void pulse(debug_info_param info) = 0; 32 virtual sema_wakeup_reason wait(bool try_wait, bool is_timed, debug_info_param info) = 0; 33 virtual bool is_signaled(debug_info_param info) = 0; 34 virtual void memory_acquire(debug_info_param info) = 0; 35 virtual void* prepare_wait(debug_info_param info) = 0; 36 virtual ~event_data() {} // just to calm down gcc 37 }; 38 39 40 41 42 template<thread_id_t thread_count> 43 class event_data_impl : public event_data 44 { 45 public: 46 event_data_impl(bool manual_reset, bool initial_state) 47 : manual_reset_(manual_reset) 48 , state_(initial_state) 49 { 50 } 51 52 ~event_data_impl() 53 { 54 //!!! detect destuction with waiters 55 } 56 57 private: 58 signature<0xdada1234> sign_; 59 bool const manual_reset_; 60 bool state_; 61 waitset<thread_count> ws_; 62 sync_var<thread_count> sync_; 63 64 struct state_event 65 { 66 enum type 67 { 68 type_set, 69 type_reset, 70 type_pulse, 71 }; 72 73 event_data_impl* addr_; 74 type type_; 75 bool initial_state_; 76 bool final_state_; 77 thread_id_t unblocked_; 78 79 void output(std::ostream& s) const 80 { 81 s << "<" << std::hex << addr_ << std::dec << "> event: "; 82 if (type_set == type_) 83 s << "set "; 84 else if (type_reset == type_) 85 s << "reset "; 86 else 87 s << "pulse "; 88 s << "initial_state=" << initial_state_ 89 << " final_state=" << final_state_; 90 if (type_reset != type_) 91 s << " unblocked=" << unblocked_; 92 } 93 94 }; 95 96 virtual void set(debug_info_param info) 97 { 98 context& c = ctx(); 99 c.sched(); 100 sign_.check(info); 101 102 bool initial_state = state_; 103 thread_id_t unblocked = 0; 104 105 if (state_) 106 { 107 //!!! probably can break if a thread waits in wfmo 108 RL_VERIFY(false == ws_); 109 } 110 else 111 { 112 sync_.release(c.threadx_); 113 state_ = true; 114 115 if (manual_reset_) 116 { 117 unblocked = ws_.unpark_all(c, info); 118 } 119 else 120 { 121 if (ws_.unpark_one(c, info)) 122 unblocked = 1; 123 } 124 } 125 126 RL_HIST(state_event) {this, state_event::type_set, initial_state, state_, unblocked} RL_HIST_END(); 127 } 128 129 virtual void reset(debug_info_param info) 130 { 131 context& c = ctx(); 132 c.sched(); 133 sign_.check(info); 134 135 bool initial_state = state_; 136 137 if (state_) 138 { 139 RL_VERIFY(false == ws_); 140 sync_.release(c.threadx_); 141 state_ = false; 142 } 143 144 RL_HIST(state_event) {this, state_event::type_reset, initial_state, state_, 0} RL_HIST_END(); 145 } 146 147 virtual void pulse(debug_info_param info) 148 { 149 context& c = ctx(); 150 c.sched(); 151 sign_.check(info); 152 153 //??? should I model nasty caveat described in MSDN 154 thread_id_t unblocked = 0; 155 156 if (state_) 157 { 158 //!!! probably can break if a thread waits in wfmo 159 RL_VERIFY(false == ws_); 160 } 161 else 162 { 163 sync_.release(c.threadx_); 164 state_ = true; 165 unblocked = ws_.unpark_all(c, info); 166 state_ = false; 167 } 168 169 RL_HIST(state_event) {this, state_event::type_pulse, state_, state_, unblocked} RL_HIST_END(); 170 } 171 172 struct wait_event 173 { 174 event_data_impl* addr_; 175 bool try_wait_; 176 bool is_timed_; 177 bool initial_state_; 178 bool final_state_; 179 sema_wakeup_reason reason_; 180 181 void output(std::ostream& s) const 182 { 183 s << "<" << std::hex << addr_ << std::dec << "> event: "; 184 if (try_wait_) 185 s << "try_wait "; 186 else if (is_timed_) 187 s << "timed wait "; 188 else 189 s << "wait "; 190 191 if (reason_ == sema_wakeup_reason_success) 192 s << "succeeded "; 193 else if (reason_ == sema_wakeup_reason_failed) 194 s << "failed "; 195 else if (reason_ == sema_wakeup_reason_timeout) 196 s << "timed out "; 197 else if (reason_ == sema_wakeup_reason_spurious) 198 s << "spuriously failed "; 199 200 s << "initial_state=" << initial_state_ 201 << " final_state=" << final_state_; 202 } 203 }; 204 205 virtual sema_wakeup_reason wait(bool try_wait, bool is_timed, debug_info_param info) 206 { 207 context& c = ctx(); 208 c.sched(); 209 sign_.check(info); 210 211 bool initial_state = state_; 212 sema_wakeup_reason reason = sema_wakeup_reason_success; 213 214 for (;;) 215 { 216 if (state_) 217 { 218 if (manual_reset_) 219 { 220 sync_.acquire(c.threadx_); 221 } 222 else 223 { 224 state_ = false; 225 sync_.acq_rel(c.threadx_); 226 } 227 reason = sema_wakeup_reason_success; 228 break; 229 } 230 231 if (try_wait) 232 { 233 sync_.acquire(c.threadx_); 234 reason = sema_wakeup_reason_failed; 235 break; 236 } 237 238 unpark_reason wr = ws_.park_current(c, is_timed, false, true, info); 239 initial_state = state_; 240 if (unpark_reason_timeout == wr) 241 { 242 sync_.acquire(c.threadx_); 243 reason = sema_wakeup_reason_timeout; 244 break; 245 } 246 else if (unpark_reason_normal == wr) 247 { 248 RL_VERIFY(state_ == true); 249 if (manual_reset_) 250 { 251 sync_.acquire(c.threadx_); 252 } 253 else 254 { 255 state_ = false; 256 sync_.acq_rel(c.threadx_); 257 } 258 c.switch_back(info); 259 reason = sema_wakeup_reason_success; 260 break; 261 } 262 RL_VERIFY(false); 263 } 264 265 RL_HIST(wait_event) {this, try_wait, is_timed, initial_state, state_, reason} RL_HIST_END(); 266 return reason; 267 } 268 269 virtual bool is_signaled(debug_info_param info) 270 { 271 (void)info; 272 return state_; 273 } 274 275 virtual void memory_acquire(debug_info_param info) 276 { 277 (void)info; 278 sync_.acquire(ctx().threadx_); 279 } 280 281 virtual void* prepare_wait(debug_info_param info) 282 { 283 (void)info; 284 return &ws_; 285 } 286 287 RL_NOCOPY(event_data_impl); 288 }; 289 290 291 292 class generic_event : public win_waitable_object 293 { 294 public: 295 generic_event() 296 : impl_() 297 { 298 } 299 300 generic_event(generic_event const&) 301 : impl_() 302 { 303 } 304 305 generic_event& operator = (generic_event const&) 306 { 307 return *this; 308 } 309 310 void init(bool manual_reset, bool initial_state, debug_info_param info) 311 { 312 context& c = ctx(); 313 RL_ASSERT_IMPL(0 == impl_, test_result_double_initialization_of_event, "", info); 314 sign_.check(info); 315 impl_ = c.event_ctor(manual_reset, initial_state); 316 } 317 318 void deinit(debug_info_param info) 319 { 320 context& c = ctx(); 321 check(info); 322 c.event_dtor(impl_); 323 impl_ = 0; 324 } 325 326 void set(debug_info_param info) 327 { 328 check(info); 329 impl_->set(info); 330 } 331 332 void reset(debug_info_param info) 333 { 334 check(info); 335 impl_->reset(info); 336 } 337 338 void pulse(debug_info_param info) 339 { 340 check(info); 341 impl_->pulse(info); 342 } 343 344 virtual sema_wakeup_reason wait(bool try_wait, bool is_timed, debug_info_param info) 345 { 346 check(info); 347 return impl_->wait(try_wait, is_timed, info); 348 } 349 350 virtual bool signal(debug_info_param info) 351 { 352 set(info); 353 return true; 354 } 355 356 private: 357 event_data* impl_; 358 signature<0x3390eeaa> sign_; 359 360 event_data* check(debug_info_param info) 361 { 362 RL_ASSERT_IMPL(impl_, test_result_usage_of_non_initialized_event, "", info); 363 sign_.check(info); 364 return impl_; 365 } 366 367 virtual bool is_signaled(debug_info_param info) 368 { 369 return check(info)->is_signaled(info); 370 } 371 372 virtual void memory_acquire(debug_info_param info) 373 { 374 check(info)->memory_acquire(info); 375 } 376 377 virtual void* prepare_wait(debug_info_param info) 378 { 379 return check(info)->prepare_wait(info); 380 } 381 }; 382 383 384 } 385 386 #endif