xref: /aosp_15_r20/external/cronet/base/synchronization/waitable_event.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
6 #define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
7 
8 #include <stddef.h>
9 
10 #include "base/base_export.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/raw_ptr.h"
13 #include "build/build_config.h"
14 
15 #if BUILDFLAG(IS_WIN)
16 #include "base/win/scoped_handle.h"
17 #elif BUILDFLAG(IS_APPLE)
18 #include <mach/mach.h>
19 
20 #include <list>
21 #include <memory>
22 
23 #include "base/apple/scoped_mach_port.h"
24 #include "base/functional/callback_forward.h"
25 #include "base/memory/ref_counted.h"
26 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
27 #include <list>
28 #include <utility>
29 
30 #include "base/memory/ref_counted.h"
31 #include "base/synchronization/lock.h"
32 #endif
33 
34 namespace base {
35 
36 class TimeDelta;
37 
38 // A WaitableEvent can be a useful thread synchronization tool when you want to
39 // allow one thread to wait for another thread to finish some work. For
40 // non-Windows systems, this can only be used from within a single address
41 // space.
42 //
43 // Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
44 // protect a simple boolean value.  However, if you find yourself using a
45 // WaitableEvent in conjunction with a Lock to wait for a more complex state
46 // change (e.g., for an item to be added to a queue), then you should probably
47 // be using a ConditionVariable instead of a WaitableEvent.
48 //
49 // NOTE: On Windows, this class provides a subset of the functionality afforded
50 // by a Windows event object.  This is intentional.  If you are writing Windows
51 // specific code and you need other features of a Windows event, then you might
52 // be better off just using an Windows event directly.
53 class BASE_EXPORT WaitableEvent {
54  public:
55   // Indicates whether a WaitableEvent should automatically reset the event
56   // state after a single waiting thread has been released or remain signaled
57   // until Reset() is manually invoked.
58   enum class ResetPolicy { MANUAL, AUTOMATIC };
59 
60   // Indicates whether a new WaitableEvent should start in a signaled state or
61   // not.
62   enum class InitialState { SIGNALED, NOT_SIGNALED };
63 
64   // Constructs a WaitableEvent with policy and initial state as detailed in
65   // the above enums.
66   WaitableEvent(ResetPolicy reset_policy = ResetPolicy::MANUAL,
67                 InitialState initial_state = InitialState::NOT_SIGNALED);
68 
69 #if BUILDFLAG(IS_WIN)
70   // Create a WaitableEvent from an Event HANDLE which has already been
71   // created. This objects takes ownership of the HANDLE and will close it when
72   // deleted.
73   explicit WaitableEvent(win::ScopedHandle event_handle);
74 #endif
75 
76   WaitableEvent(const WaitableEvent&) = delete;
77   WaitableEvent& operator=(const WaitableEvent&) = delete;
78 
79   ~WaitableEvent();
80 
81   // Put the event in the un-signaled state.
82   void Reset();
83 
84   // Put the event in the signaled state.  Causing any thread blocked on Wait
85   // to be woken up.
86   void Signal();
87 
88   // Returns true if the event is in the signaled state, else false.  If this
89   // is not a manual reset event, then this test will cause a reset.
90   bool IsSignaled();
91 
92   // Wait indefinitely for the event to be signaled. Wait's return "happens
93   // after" |Signal| has completed. This means that it's safe for a
94   // WaitableEvent to synchronise its own destruction, like this:
95   //
96   //   WaitableEvent *e = new WaitableEvent;
97   //   SendToOtherThread(e);
98   //   e->Wait();
99   //   delete e;
100   NOT_TAIL_CALLED void Wait();
101 
102   // Wait up until wait_delta has passed for the event to be signaled
103   // (real-time; ignores time overrides).  Returns true if the event was
104   // signaled. Handles spurious wakeups and guarantees that |wait_delta| will
105   // have elapsed if this returns false.
106   //
107   // TimedWait can synchronise its own destruction like |Wait|.
108   NOT_TAIL_CALLED bool TimedWait(TimeDelta wait_delta);
109 
110 #if BUILDFLAG(IS_WIN)
handle()111   HANDLE handle() const { return handle_.get(); }
112 #endif
113 
114   // Declares that this WaitableEvent will only ever be used by a thread that is
115   // idle at the bottom of its stack and waiting for work (in particular, it is
116   // not synchronously waiting on this event before resuming ongoing work). This
117   // is useful to avoid telling base-internals that this thread is "blocked"
118   // when it's merely idle and ready to do work. As such, this is only expected
119   // to be used by thread and thread pool impls. In such cases wakeup.flow
120   // events aren't emitted on |Signal|/|Wait|, because threading implementations
121   // are responsible for emitting the cause of their wakeup from idle.
declare_only_used_while_idle()122   void declare_only_used_while_idle() { only_used_while_idle_ = true; }
123 
124   // Wait, synchronously, on multiple events.
125   //   waitables: an array of WaitableEvent pointers
126   //   count: the number of elements in @waitables
127   //
128   // returns: the index of a WaitableEvent which has been signaled.
129   //
130   // You MUST NOT delete any of the WaitableEvent objects while this wait is
131   // happening, however WaitMany's return "happens after" the |Signal| call
132   // that caused it has completed, like |Wait|.
133   //
134   // If more than one WaitableEvent is signaled to unblock WaitMany, the lowest
135   // index among them is returned.
136   NOT_TAIL_CALLED static size_t WaitMany(WaitableEvent** waitables,
137                                          size_t count);
138 
139   // For asynchronous waiting, see WaitableEventWatcher
140 
141   // This is a private helper class. It's here because it's used by friends of
142   // this class (such as WaitableEventWatcher) to be able to enqueue elements
143   // of the wait-list
144   class Waiter {
145    public:
146     // Signal the waiter to wake up.
147     //
148     // Consider the case of a Waiter which is in multiple WaitableEvent's
149     // wait-lists. Each WaitableEvent is automatic-reset and two of them are
150     // signaled at the same time. Now, each will wake only the first waiter in
151     // the wake-list before resetting. However, if those two waiters happen to
152     // be the same object (as can happen if another thread didn't have a chance
153     // to dequeue the waiter from the other wait-list in time), two auto-resets
154     // will have happened, but only one waiter has been signaled!
155     //
156     // Because of this, a Waiter may "reject" a wake by returning false. In
157     // this case, the auto-reset WaitableEvent shouldn't act as if anything has
158     // been notified.
159     virtual bool Fire(WaitableEvent* signaling_event) = 0;
160 
161     // Waiters may implement this in order to provide an extra condition for
162     // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
163     // pointers match then this function is called as a final check. See the
164     // comments in ~Handle for why.
165     virtual bool Compare(void* tag) = 0;
166 
167    protected:
168     virtual ~Waiter() = default;
169   };
170 
171  private:
172   friend class WaitableEventWatcher;
173 
174   // The platform specific portions of Signal, TimedWait, and WaitMany (which do
175   // the actual signaling and waiting).
176   void SignalImpl();
177   bool TimedWaitImpl(TimeDelta wait_delta);
178   static size_t WaitManyImpl(WaitableEvent** waitables, size_t count);
179 
180 #if BUILDFLAG(IS_WIN)
181   win::ScopedHandle handle_;
182 #elif BUILDFLAG(IS_APPLE)
183   // Peeks the message queue named by |port| and returns true if a message
184   // is present and false if not. If |dequeue| is true, the messsage will be
185   // drained from the queue. If |dequeue| is false, the queue will only be
186   // peeked. |port| must be a receive right.
187   static bool PeekPort(mach_port_t port, bool dequeue);
188 
189   // The Mach receive right is waited on by both WaitableEvent and
190   // WaitableEventWatcher. It is valid to signal and then delete an event, and
191   // a watcher should still be notified. If the right were to be destroyed
192   // immediately, the watcher would not receive the signal. Because Mach
193   // receive rights cannot have a user refcount greater than one, the right
194   // must be reference-counted manually.
195   class ReceiveRight : public RefCountedThreadSafe<ReceiveRight> {
196    public:
197     explicit ReceiveRight(mach_port_t name);
198 
199     ReceiveRight(const ReceiveRight&) = delete;
200     ReceiveRight& operator=(const ReceiveRight&) = delete;
201 
Name()202     mach_port_t Name() const { return right_.get(); }
203 
204    private:
205     friend class RefCountedThreadSafe<ReceiveRight>;
206     ~ReceiveRight();
207 
208     apple::ScopedMachReceiveRight right_;
209   };
210 
211   const ResetPolicy policy_;
212 
213   // The receive right for the event.
214   scoped_refptr<ReceiveRight> receive_right_;
215 
216   // The send right used to signal the event. This can be disposed of with
217   // the event, unlike the receive right, since a deleted event cannot be
218   // signaled.
219   apple::ScopedMachSendRight send_right_;
220 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
221   // On Windows, you must not close a HANDLE which is currently being waited on.
222   // The MSDN documentation says that the resulting behaviour is 'undefined'.
223   // To solve that issue each WaitableEventWatcher duplicates the given event
224   // handle.
225 
226   // However, if we were to include the following members
227   // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
228   // event which gets deleted. This mismatch has bitten us several times now,
229   // so we have a kernel of the WaitableEvent, which is reference counted.
230   // WaitableEventWatchers may then take a reference and thus match the Windows
231   // behaviour.
232   struct WaitableEventKernel :
233       public RefCountedThreadSafe<WaitableEventKernel> {
234    public:
235     WaitableEventKernel(ResetPolicy reset_policy, InitialState initial_state);
236 
237     bool Dequeue(Waiter* waiter, void* tag);
238 
239     base::Lock lock_;
240     const bool manual_reset_;
241     bool signaled_;
242     std::list<raw_ptr<Waiter, CtnExperimental>> waiters_;
243 
244    private:
245     friend class RefCountedThreadSafe<WaitableEventKernel>;
246     ~WaitableEventKernel();
247   };
248 
249   typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
250 
251   // When dealing with arrays of WaitableEvent*, we want to sort by the address
252   // of the WaitableEvent in order to have a globally consistent locking order.
253   // In that case we keep them, in sorted order, in an array of pairs where the
254   // second element is the index of the WaitableEvent in the original,
255   // unsorted, array.
256   static size_t EnqueueMany(WaiterAndIndex* waitables,
257                             size_t count, Waiter* waiter);
258 
259   bool SignalAll();
260   bool SignalOne();
261   void Enqueue(Waiter* waiter);
262 
263   scoped_refptr<WaitableEventKernel> kernel_;
264 #endif
265 
266   // Whether a thread invoking Wait() on this WaitableEvent should be considered
267   // blocked as opposed to idle (and potentially replaced if part of a pool),
268   // and whether WaitableEvent should emit a wakeup.flow event on Signal =>
269   // TimedWait.
270   bool only_used_while_idle_ = false;
271 };
272 
273 }  // namespace base
274 
275 #endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
276