waitable_event_posix.cc (15209B)
1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stddef.h> 6 7 #include <limits> 8 #include <vector> 9 10 #include "base/check_op.h" 11 #include "base/memory/raw_ptr.h" 12 #include "base/ranges/algorithm.h" 13 #include "base/synchronization/condition_variable.h" 14 #include "base/synchronization/lock.h" 15 #include "base/synchronization/waitable_event.h" 16 #include "base/threading/scoped_blocking_call.h" 17 #include "base/threading/thread_restrictions.h" 18 #include "base/time/time.h" 19 #include "base/time/time_override.h" 20 #include "third_party/abseil-cpp/absl/types/optional.h" 21 22 // ----------------------------------------------------------------------------- 23 // A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't 24 // support cross-process events (where one process can signal an event which 25 // others are waiting on). Because of this, we can avoid having one thread per 26 // listener in several cases. 27 // 28 // The WaitableEvent maintains a list of waiters, protected by a lock. Each 29 // waiter is either an async wait, in which case we have a Task and the 30 // MessageLoop to run it on, or a blocking wait, in which case we have the 31 // condition variable to signal. 32 // 33 // Waiting involves grabbing the lock and adding oneself to the wait list. Async 34 // waits can be canceled, which means grabbing the lock and removing oneself 35 // from the list. 36 // 37 // Waiting on multiple events is handled by adding a single, synchronous wait to 38 // the wait-list of many events. An event passes a pointer to itself when 39 // firing a waiter and so we can store that pointer to find out which event 40 // triggered. 41 // ----------------------------------------------------------------------------- 42 43 namespace base { 44 45 // ----------------------------------------------------------------------------- 46 // This is just an abstract base class for waking the two types of waiters 47 // ----------------------------------------------------------------------------- 48 WaitableEvent::WaitableEvent(ResetPolicy reset_policy, 49 InitialState initial_state) 50 : kernel_(new WaitableEventKernel(reset_policy, initial_state)) {} 51 52 WaitableEvent::~WaitableEvent() = default; 53 54 void WaitableEvent::Reset() { 55 base::AutoLock locked(kernel_->lock_); 56 kernel_->signaled_ = false; 57 } 58 59 void WaitableEvent::SignalImpl() { 60 base::AutoLock locked(kernel_->lock_); 61 62 if (kernel_->signaled_) 63 return; 64 65 if (kernel_->manual_reset_) { 66 SignalAll(); 67 kernel_->signaled_ = true; 68 } else { 69 // In the case of auto reset, if no waiters were woken, we remain 70 // signaled. 71 if (!SignalOne()) 72 kernel_->signaled_ = true; 73 } 74 } 75 76 bool WaitableEvent::IsSignaled() { 77 base::AutoLock locked(kernel_->lock_); 78 79 const bool result = kernel_->signaled_; 80 if (result && !kernel_->manual_reset_) 81 kernel_->signaled_ = false; 82 return result; 83 } 84 85 // ----------------------------------------------------------------------------- 86 // Synchronous waits 87 88 // ----------------------------------------------------------------------------- 89 // This is a synchronous waiter. The thread is waiting on the given condition 90 // variable and the fired flag in this object. 91 // ----------------------------------------------------------------------------- 92 class SyncWaiter : public WaitableEvent::Waiter { 93 public: 94 SyncWaiter() 95 : fired_(false), signaling_event_(nullptr), lock_(), cv_(&lock_) {} 96 97 bool Fire(WaitableEvent* signaling_event) override { 98 base::AutoLock locked(lock_); 99 100 if (fired_) 101 return false; 102 103 fired_ = true; 104 signaling_event_ = signaling_event; 105 106 cv_.Broadcast(); 107 108 // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on 109 // the blocking thread's stack. There is no |delete this;| in Fire. The 110 // SyncWaiter object is destroyed when it goes out of scope. 111 112 return true; 113 } 114 115 WaitableEvent* signaling_event() const { 116 return signaling_event_; 117 } 118 119 // --------------------------------------------------------------------------- 120 // These waiters are always stack allocated and don't delete themselves. Thus 121 // there's no problem and the ABA tag is the same as the object pointer. 122 // --------------------------------------------------------------------------- 123 bool Compare(void* tag) override { return this == tag; } 124 125 // --------------------------------------------------------------------------- 126 // Called with lock held. 127 // --------------------------------------------------------------------------- 128 bool fired() const { 129 return fired_; 130 } 131 132 // --------------------------------------------------------------------------- 133 // During a TimedWait, we need a way to make sure that an auto-reset 134 // WaitableEvent doesn't think that this event has been signaled between 135 // unlocking it and removing it from the wait-list. Called with lock held. 136 // --------------------------------------------------------------------------- 137 void Disable() { 138 fired_ = true; 139 } 140 141 base::Lock* lock() { 142 return &lock_; 143 } 144 145 base::ConditionVariable* cv() { 146 return &cv_; 147 } 148 149 private: 150 bool fired_; 151 raw_ptr<WaitableEvent> signaling_event_; // The WaitableEvent which woke us 152 base::Lock lock_; 153 base::ConditionVariable cv_; 154 }; 155 156 bool WaitableEvent::TimedWaitImpl(TimeDelta wait_delta) { 157 kernel_->lock_.Acquire(); 158 if (kernel_->signaled_) { 159 if (!kernel_->manual_reset_) { 160 // In this case we were signaled when we had no waiters. Now that 161 // someone has waited upon us, we can automatically reset. 162 kernel_->signaled_ = false; 163 } 164 165 kernel_->lock_.Release(); 166 return true; 167 } 168 169 SyncWaiter sw; 170 if (only_used_while_idle_) { 171 sw.cv()->declare_only_used_while_idle(); 172 } 173 sw.lock()->Acquire(); 174 175 Enqueue(&sw); 176 kernel_->lock_.Release(); 177 // We are violating locking order here by holding the SyncWaiter lock but not 178 // the WaitableEvent lock. However, this is safe because we don't lock |lock_| 179 // again before unlocking it. 180 181 // TimeTicks takes care of overflow but we special case is_max() nonetheless 182 // to avoid invoking TimeTicksNowIgnoringOverride() unnecessarily (same for 183 // the increment step of the for loop if the condition variable returns 184 // early). Ref: https://crbug.com/910524#c7 185 const TimeTicks end_time = 186 wait_delta.is_max() ? TimeTicks::Max() 187 : subtle::TimeTicksNowIgnoringOverride() + wait_delta; 188 for (TimeDelta remaining = wait_delta; remaining.is_positive() && !sw.fired(); 189 remaining = end_time.is_max() 190 ? TimeDelta::Max() 191 : end_time - subtle::TimeTicksNowIgnoringOverride()) { 192 if (end_time.is_max()) 193 sw.cv()->Wait(); 194 else 195 sw.cv()->TimedWait(remaining); 196 } 197 198 // Get the SyncWaiter signaled state before releasing the lock. 199 const bool return_value = sw.fired(); 200 201 // We can't acquire |lock_| before releasing the SyncWaiter lock (because of 202 // locking order), however, in between the two a signal could be fired and 203 // |sw| would accept it, however we will still return false, so the signal 204 // would be lost on an auto-reset WaitableEvent. Thus we call Disable which 205 // makes sw::Fire return false. 206 sw.Disable(); 207 sw.lock()->Release(); 208 209 // This is a bug that has been enshrined in the interface of WaitableEvent 210 // now: |Dequeue| is called even when |sw.fired()| is true, even though it'll 211 // always return false in that case. However, taking the lock ensures that 212 // |Signal| has completed before we return and means that a WaitableEvent can 213 // synchronise its own destruction. 214 kernel_->lock_.Acquire(); 215 kernel_->Dequeue(&sw, &sw); 216 kernel_->lock_.Release(); 217 218 return return_value; 219 } 220 221 // ----------------------------------------------------------------------------- 222 // Synchronous waiting on multiple objects. 223 224 static bool // StrictWeakOrdering 225 cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a, 226 const std::pair<WaitableEvent*, unsigned> &b) { 227 return a.first < b.first; 228 } 229 230 // static 231 // NO_THREAD_SAFETY_ANALYSIS: Complex control flow. 232 size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, 233 size_t count) NO_THREAD_SAFETY_ANALYSIS { 234 DCHECK(count) << "Cannot wait on no events"; 235 internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call( 236 FROM_HERE, BlockingType::MAY_BLOCK); 237 // We need to acquire the locks in a globally consistent order. Thus we sort 238 // the array of waitables by address. We actually sort a pairs so that we can 239 // map back to the original index values later. 240 std::vector<std::pair<WaitableEvent*, size_t> > waitables; 241 waitables.reserve(count); 242 for (size_t i = 0; i < count; ++i) 243 waitables.push_back(std::make_pair(raw_waitables[i], i)); 244 245 DCHECK_EQ(count, waitables.size()); 246 247 ranges::sort(waitables, cmp_fst_addr); 248 249 // The set of waitables must be distinct. Since we have just sorted by 250 // address, we can check this cheaply by comparing pairs of consecutive 251 // elements. 252 for (size_t i = 0; i < waitables.size() - 1; ++i) { 253 DCHECK(waitables[i].first != waitables[i+1].first); 254 } 255 256 SyncWaiter sw; 257 258 const size_t r = EnqueueMany(&waitables[0], count, &sw); 259 if (r < count) { 260 // One of the events is already signaled. The SyncWaiter has not been 261 // enqueued anywhere. 262 return waitables[r].second; 263 } 264 265 // At this point, we hold the locks on all the WaitableEvents and we have 266 // enqueued our waiter in them all. 267 sw.lock()->Acquire(); 268 // Release the WaitableEvent locks in the reverse order 269 for (size_t i = 0; i < count; ++i) { 270 waitables[count - (1 + i)].first->kernel_->lock_.Release(); 271 } 272 273 for (;;) { 274 if (sw.fired()) 275 break; 276 277 sw.cv()->Wait(); 278 } 279 sw.lock()->Release(); 280 281 // The address of the WaitableEvent which fired is stored in the SyncWaiter. 282 WaitableEvent *const signaled_event = sw.signaling_event(); 283 // This will store the index of the raw_waitables which fired. 284 size_t signaled_index = 0; 285 286 // Take the locks of each WaitableEvent in turn (except the signaled one) and 287 // remove our SyncWaiter from the wait-list 288 for (size_t i = 0; i < count; ++i) { 289 if (raw_waitables[i] != signaled_event) { 290 raw_waitables[i]->kernel_->lock_.Acquire(); 291 // There's no possible ABA issue with the address of the SyncWaiter here 292 // because it lives on the stack. Thus the tag value is just the pointer 293 // value again. 294 raw_waitables[i]->kernel_->Dequeue(&sw, &sw); 295 raw_waitables[i]->kernel_->lock_.Release(); 296 } else { 297 // By taking this lock here we ensure that |Signal| has completed by the 298 // time we return, because |Signal| holds this lock. This matches the 299 // behaviour of |Wait| and |TimedWait|. 300 raw_waitables[i]->kernel_->lock_.Acquire(); 301 raw_waitables[i]->kernel_->lock_.Release(); 302 signaled_index = i; 303 } 304 } 305 306 return signaled_index; 307 } 308 309 // ----------------------------------------------------------------------------- 310 // If return value == count: 311 // The locks of the WaitableEvents have been taken in order and the Waiter has 312 // been enqueued in the wait-list of each. None of the WaitableEvents are 313 // currently signaled 314 // else: 315 // None of the WaitableEvent locks are held. The Waiter has not been enqueued 316 // in any of them and the return value is the index of the WaitableEvent which 317 // was signaled with the lowest input index from the original WaitMany call. 318 // ----------------------------------------------------------------------------- 319 // static 320 // NO_THREAD_SAFETY_ANALYSIS: Complex control flow. 321 size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables, 322 size_t count, 323 Waiter* waiter) NO_THREAD_SAFETY_ANALYSIS { 324 size_t winner = count; 325 size_t winner_index = count; 326 for (size_t i = 0; i < count; ++i) { 327 auto& kernel = waitables[i].first->kernel_; 328 kernel->lock_.Acquire(); 329 if (kernel->signaled_ && waitables[i].second < winner) { 330 winner = waitables[i].second; 331 winner_index = i; 332 } 333 } 334 335 // No events signaled. All locks acquired. Enqueue the Waiter on all of them 336 // and return. 337 if (winner == count) { 338 for (size_t i = 0; i < count; ++i) 339 waitables[i].first->Enqueue(waiter); 340 return count; 341 } 342 343 // Unlock in reverse order and possibly clear the chosen winner's signal 344 // before returning its index. 345 for (auto* w = waitables + count - 1; w >= waitables; --w) { 346 auto& kernel = w->first->kernel_; 347 if (w->second == winner) { 348 if (!kernel->manual_reset_) 349 kernel->signaled_ = false; 350 } 351 kernel->lock_.Release(); 352 } 353 354 return winner_index; 355 } 356 357 // ----------------------------------------------------------------------------- 358 359 360 // ----------------------------------------------------------------------------- 361 // Private functions... 362 363 WaitableEvent::WaitableEventKernel::WaitableEventKernel( 364 ResetPolicy reset_policy, 365 InitialState initial_state) 366 : manual_reset_(reset_policy == ResetPolicy::MANUAL), 367 signaled_(initial_state == InitialState::SIGNALED) {} 368 369 WaitableEvent::WaitableEventKernel::~WaitableEventKernel() = default; 370 371 // ----------------------------------------------------------------------------- 372 // Wake all waiting waiters. Called with lock held. 373 // ----------------------------------------------------------------------------- 374 bool WaitableEvent::SignalAll() { 375 bool signaled_at_least_one = false; 376 377 for (auto* i : kernel_->waiters_) { 378 if (i->Fire(this)) 379 signaled_at_least_one = true; 380 } 381 382 kernel_->waiters_.clear(); 383 return signaled_at_least_one; 384 } 385 386 // --------------------------------------------------------------------------- 387 // Try to wake a single waiter. Return true if one was woken. Called with lock 388 // held. 389 // --------------------------------------------------------------------------- 390 bool WaitableEvent::SignalOne() { 391 for (;;) { 392 if (kernel_->waiters_.empty()) 393 return false; 394 395 const bool r = (*kernel_->waiters_.begin())->Fire(this); 396 kernel_->waiters_.pop_front(); 397 if (r) 398 return true; 399 } 400 } 401 402 // ----------------------------------------------------------------------------- 403 // Add a waiter to the list of those waiting. Called with lock held. 404 // ----------------------------------------------------------------------------- 405 void WaitableEvent::Enqueue(Waiter* waiter) { 406 kernel_->waiters_.push_back(waiter); 407 } 408 409 // ----------------------------------------------------------------------------- 410 // Remove a waiter from the list of those waiting. Return true if the waiter was 411 // actually removed. Called with lock held. 412 // ----------------------------------------------------------------------------- 413 bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) { 414 for (auto i = waiters_.begin(); i != waiters_.end(); ++i) { 415 if (*i == waiter && (*i)->Compare(tag)) { 416 waiters_.erase(i); 417 return true; 418 } 419 } 420 421 return false; 422 } 423 424 // ----------------------------------------------------------------------------- 425 426 } // namespace base