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