waitset.hpp (5582B)
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_WAITSET_HPP 11 #define RL_WAITSET_HPP 12 #ifdef _MSC_VER 13 # pragma once 14 #endif 15 16 #include "base.hpp" 17 #include "thread_base.hpp" 18 #include "context_base.hpp" 19 20 21 namespace rl 22 { 23 24 25 template<thread_id_t thread_count> 26 class waitset 27 { 28 public: 29 waitset() 30 { 31 size_ = 0; 32 } 33 34 unpark_reason park_current(context& c, 35 bool is_timed, 36 bool allow_spurious_wakeup, 37 bool do_switch, 38 debug_info_param info) 39 { 40 RL_VERIFY(size_ < thread_count); 41 thread_info_base* th = c.threadx_; 42 thread_desc desc = {th, 0, 0, 0, false, do_switch}; 43 set_[size_] = desc; 44 size_ += 1; 45 unpark_reason reason = c.park_current_thread(is_timed, allow_spurious_wakeup, do_switch, info); 46 if (reason == unpark_reason_normal) 47 { 48 if (do_switch) 49 RL_VERIFY(c.threadx_->temp_switch_from_ != -1); 50 else 51 RL_VERIFY(c.threadx_->temp_switch_from_ == -1); 52 } 53 else 54 { 55 remove(th); 56 } 57 return reason; 58 } 59 60 static unpark_reason park_current(context& c, 61 waitset** ws, 62 win_waitable_object** wo, 63 size_t count, 64 bool wait_all, 65 bool is_timed, 66 bool do_switch, 67 debug_info_param info) 68 { 69 thread_info_base* th = c.threadx_; 70 thread_desc desc = {th, (unsigned)count, ws, wo, wait_all, do_switch}; 71 for (unsigned wsi = 0; wsi != count; ++wsi) 72 { 73 RL_VERIFY(ws[wsi]->size_ < thread_count); 74 ws[wsi]->set_[ws[wsi]->size_] = desc; 75 ws[wsi]->size_ += 1; 76 } 77 unpark_reason reason = c.park_current_thread(is_timed, false, do_switch, info); 78 if (reason == unpark_reason_normal) 79 { 80 if (do_switch) 81 RL_VERIFY(c.threadx_->temp_switch_from_ != -1); 82 else 83 RL_VERIFY(c.threadx_->temp_switch_from_ == -1); 84 } 85 else 86 { 87 remove(th, ws, (unsigned)count); 88 } 89 return reason; 90 } 91 92 bool unpark_one(context& c, debug_info_param info) 93 { 94 if (0 == size_) 95 return false; 96 //!!! too high preassure on full sched 97 thread_id_t idx = c.rand(size_, sched_type_user); 98 if (try_remove(c, idx, info)) 99 return true; 100 for (idx = 0; idx != size_; idx += 1) 101 { 102 if (try_remove(c, idx, info)) 103 return true; 104 } 105 return false; 106 } 107 108 thread_id_t unpark_all(context& c, debug_info_param info) 109 { 110 thread_id_t cnt = 0; 111 for (thread_id_t idx = 0; idx != size_; idx += 1) 112 { 113 if (try_remove(c, idx, info)) 114 { 115 cnt += 1; 116 idx -= 1; 117 } 118 } 119 return cnt; 120 } 121 122 thread_id_t size() const 123 { 124 return size_; 125 } 126 127 operator bool () const 128 { 129 return 0 != size_; 130 } 131 132 private: 133 struct thread_desc 134 { 135 thread_info_base* th_; 136 unsigned count_; // 0 - wfso, !0 - wfmo 137 waitset** ws_; // 0 - wfso, !0 - wfmo 138 win_waitable_object** wo_; // 0 - wfso, !0 - wfmo 139 bool wait_all_; 140 bool do_switch_; 141 }; 142 143 thread_desc set_ [thread_count]; 144 thread_id_t size_; 145 146 bool try_remove(context& c, thread_id_t const idx, debug_info_param info) 147 { 148 RL_VERIFY(idx < size_); 149 thread_desc const& d = set_[idx]; 150 if (d.count_ != 0 && d.wait_all_ == true) 151 { 152 for (size_t i = 0; i != d.count_; i += 1) 153 { 154 if (d.wo_[i]->is_signaled(info) == false) 155 return false; 156 } 157 } 158 size_t const tid = d.th_->index_; 159 bool const do_switch = d.do_switch_; 160 if (d.ws_) 161 remove(d.th_, d.ws_, d.count_); 162 else 163 remove(d.th_); 164 c.unpark_thread(tid, do_switch, info); 165 return true; 166 } 167 168 void remove(thread_info_base* th) 169 { 170 thread_id_t size = size_; 171 thread_id_t i = 0; 172 for (; i != size; ++i) 173 { 174 if (set_[i].th_ == th) 175 break; 176 } 177 RL_VERIFY(i != size); 178 for (thread_id_t j = i + 1; j != size; ++j) 179 { 180 set_[j - 1] = set_[j]; 181 } 182 size_ -= 1; 183 } 184 185 static void remove(thread_info_base* th, waitset** ws, unsigned count) 186 { 187 for (unsigned wsi = 0; wsi != count; ++wsi) 188 { 189 ws[wsi]->remove(th); 190 } 191 } 192 }; 193 194 195 } 196 197 198 #endif