1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 #pragma once 8 9 #include "base/base_api.h" 10 #include "base/basictypes.h" 11 12 #if defined(OS_WIN) 13 #include <windows.h> 14 #endif 15 16 #if defined(OS_POSIX) 17 #include <list> 18 #include <utility> 19 #include "base/memory/ref_counted.h" 20 #include "base/synchronization/lock.h" 21 #endif 22 23 namespace base { 24 25 // This replaces INFINITE from Win32 26 static const int kNoTimeout = -1; 27 28 class TimeDelta; 29 30 // A WaitableEvent can be a useful thread synchronization tool when you want to 31 // allow one thread to wait for another thread to finish some work. For 32 // non-Windows systems, this can only be used from within a single address 33 // space. 34 // 35 // Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to 36 // protect a simple boolean value. However, if you find yourself using a 37 // WaitableEvent in conjunction with a Lock to wait for a more complex state 38 // change (e.g., for an item to be added to a queue), then you should probably 39 // be using a ConditionVariable instead of a WaitableEvent. 40 // 41 // NOTE: On Windows, this class provides a subset of the functionality afforded 42 // by a Windows event object. This is intentional. If you are writing Windows 43 // specific code and you need other features of a Windows event, then you might 44 // be better off just using an Windows event directly. 45 class BASE_API WaitableEvent { 46 public: 47 // If manual_reset is true, then to set the event state to non-signaled, a 48 // consumer must call the Reset method. If this parameter is false, then the 49 // system automatically resets the event state to non-signaled after a single 50 // waiting thread has been released. 51 WaitableEvent(bool manual_reset, bool initially_signaled); 52 53 #if defined(OS_WIN) 54 // Create a WaitableEvent from an Event HANDLE which has already been 55 // created. This objects takes ownership of the HANDLE and will close it when 56 // deleted. 57 explicit WaitableEvent(HANDLE event_handle); 58 59 // Releases ownership of the handle from this object. 60 HANDLE Release(); 61 #endif 62 63 ~WaitableEvent(); 64 65 // Put the event in the un-signaled state. 66 void Reset(); 67 68 // Put the event in the signaled state. Causing any thread blocked on Wait 69 // to be woken up. 70 void Signal(); 71 72 // Returns true if the event is in the signaled state, else false. If this 73 // is not a manual reset event, then this test will cause a reset. 74 bool IsSignaled(); 75 76 // Wait indefinitely for the event to be signaled. Returns true if the event 77 // was signaled, else false is returned to indicate that waiting failed. 78 bool Wait(); 79 80 // Wait up until max_time has passed for the event to be signaled. Returns 81 // true if the event was signaled. If this method returns false, then it 82 // does not necessarily mean that max_time was exceeded. 83 bool TimedWait(const TimeDelta& max_time); 84 85 #if defined(OS_WIN) 86 HANDLE handle() const { return handle_; } 87 #endif 88 89 // Wait, synchronously, on multiple events. 90 // waitables: an array of WaitableEvent pointers 91 // count: the number of elements in @waitables 92 // 93 // returns: the index of a WaitableEvent which has been signaled. 94 // 95 // You MUST NOT delete any of the WaitableEvent objects while this wait is 96 // happening. 97 static size_t WaitMany(WaitableEvent** waitables, size_t count); 98 99 // For asynchronous waiting, see WaitableEventWatcher 100 101 // This is a private helper class. It's here because it's used by friends of 102 // this class (such as WaitableEventWatcher) to be able to enqueue elements 103 // of the wait-list 104 class Waiter { 105 public: 106 // Signal the waiter to wake up. 107 // 108 // Consider the case of a Waiter which is in multiple WaitableEvent's 109 // wait-lists. Each WaitableEvent is automatic-reset and two of them are 110 // signaled at the same time. Now, each will wake only the first waiter in 111 // the wake-list before resetting. However, if those two waiters happen to 112 // be the same object (as can happen if another thread didn't have a chance 113 // to dequeue the waiter from the other wait-list in time), two auto-resets 114 // will have happened, but only one waiter has been signaled! 115 // 116 // Because of this, a Waiter may "reject" a wake by returning false. In 117 // this case, the auto-reset WaitableEvent shouldn't act as if anything has 118 // been notified. 119 virtual bool Fire(WaitableEvent* signaling_event) = 0; 120 121 // Waiters may implement this in order to provide an extra condition for 122 // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the 123 // pointers match then this function is called as a final check. See the 124 // comments in ~Handle for why. 125 virtual bool Compare(void* tag) = 0; 126 127 protected: 128 virtual ~Waiter() {} 129 }; 130 131 private: 132 friend class WaitableEventWatcher; 133 134 #if defined(OS_WIN) 135 HANDLE handle_; 136 #else 137 // On Windows, one can close a HANDLE which is currently being waited on. The 138 // MSDN documentation says that the resulting behaviour is 'undefined', but 139 // it doesn't crash. However, if we were to include the following members 140 // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an 141 // event which gets deleted. This mismatch has bitten us several times now, 142 // so we have a kernel of the WaitableEvent, which is reference counted. 143 // WaitableEventWatchers may then take a reference and thus match the Windows 144 // behaviour. 145 struct WaitableEventKernel : 146 public RefCountedThreadSafe<WaitableEventKernel> { 147 public: 148 WaitableEventKernel(bool manual_reset, bool initially_signaled); 149 virtual ~WaitableEventKernel(); 150 151 bool Dequeue(Waiter* waiter, void* tag); 152 153 base::Lock lock_; 154 const bool manual_reset_; 155 bool signaled_; 156 std::list<Waiter*> waiters_; 157 }; 158 159 typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex; 160 161 // When dealing with arrays of WaitableEvent*, we want to sort by the address 162 // of the WaitableEvent in order to have a globally consistent locking order. 163 // In that case we keep them, in sorted order, in an array of pairs where the 164 // second element is the index of the WaitableEvent in the original, 165 // unsorted, array. 166 static size_t EnqueueMany(WaiterAndIndex* waitables, 167 size_t count, Waiter* waiter); 168 169 bool SignalAll(); 170 bool SignalOne(); 171 void Enqueue(Waiter* waiter); 172 173 scoped_refptr<WaitableEventKernel> kernel_; 174 #endif 175 176 DISALLOW_COPY_AND_ASSIGN(WaitableEvent); 177 }; 178 179 } // namespace base 180 181 #endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ 182