// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #include "base/synchronization/waitable_event.h" #include <stddef.h> #include <limits> #include <optional> #include <vector> #include "base/check_op.h" #include "base/memory/stack_allocated.h" #include "base/ranges/algorithm.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "base/threading/scoped_blocking_call.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/time/time_override.h" // ----------------------------------------------------------------------------- // A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't // support cross-process events (where one process can signal an event which // others are waiting on). Because of this, we can avoid having one thread per // listener in several cases. // // The WaitableEvent maintains a list of waiters, protected by a lock. Each // waiter is either an async wait, in which case we have a Task and the // MessageLoop to run it on, or a blocking wait, in which case we have the // condition variable to signal. // // Waiting involves grabbing the lock and adding oneself to the wait list. Async // waits can be canceled, which means grabbing the lock and removing oneself // from the list. // // Waiting on multiple events is handled by adding a single, synchronous wait to // the wait-list of many events. An event passes a pointer to itself when // firing a waiter and so we can store that pointer to find out which event // triggered. // ----------------------------------------------------------------------------- namespace base { // ----------------------------------------------------------------------------- // This is just an abstract base class for waking the two types of waiters // ----------------------------------------------------------------------------- WaitableEvent::WaitableEvent(ResetPolicy reset_policy, InitialState initial_state) : … { … } void WaitableEvent::Reset() { … } void WaitableEvent::SignalImpl() { … } bool WaitableEvent::IsSignaled() const { … } // ----------------------------------------------------------------------------- // Synchronous waits // ----------------------------------------------------------------------------- // This is a synchronous waiter. The thread is waiting on the given condition // variable and the fired flag in this object. // ----------------------------------------------------------------------------- class SyncWaiter : public WaitableEvent::Waiter { … }; bool WaitableEvent::TimedWaitImpl(TimeDelta wait_delta) { … } // ----------------------------------------------------------------------------- // Synchronous waiting on multiple objects. static bool // StrictWeakOrdering cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a, const std::pair<WaitableEvent*, unsigned> &b) { … } // static // NO_THREAD_SAFETY_ANALYSIS: Complex control flow. size_t WaitableEvent::WaitManyImpl(WaitableEvent** raw_waitables, size_t count) NO_THREAD_SAFETY_ANALYSIS { … } // ----------------------------------------------------------------------------- // If return value == count: // The locks of the WaitableEvents have been taken in order and the Waiter has // been enqueued in the wait-list of each. None of the WaitableEvents are // currently signaled // else: // None of the WaitableEvent locks are held. The Waiter has not been enqueued // in any of them and the return value is the index of the WaitableEvent which // was signaled with the lowest input index from the original WaitMany call. // ----------------------------------------------------------------------------- // static // NO_THREAD_SAFETY_ANALYSIS: Complex control flow. size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables, size_t count, Waiter* waiter) NO_THREAD_SAFETY_ANALYSIS { … } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Private functions... WaitableEvent::WaitableEventKernel::WaitableEventKernel( ResetPolicy reset_policy, InitialState initial_state) : … { … } WaitableEvent::WaitableEventKernel::~WaitableEventKernel() = default; // ----------------------------------------------------------------------------- // Wake all waiting waiters. Called with lock held. // ----------------------------------------------------------------------------- bool WaitableEvent::SignalAll() { … } // --------------------------------------------------------------------------- // Try to wake a single waiter. Return true if one was woken. Called with lock // held. // --------------------------------------------------------------------------- bool WaitableEvent::SignalOne() { … } // ----------------------------------------------------------------------------- // Add a waiter to the list of those waiting. Called with lock held. // ----------------------------------------------------------------------------- void WaitableEvent::Enqueue(Waiter* waiter) { … } // ----------------------------------------------------------------------------- // Remove a waiter from the list of those waiting. Return true if the waiter was // actually removed. Called with lock held. // ----------------------------------------------------------------------------- bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) { … } // ----------------------------------------------------------------------------- } // namespace base