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