Index: base/waitable_event.h |
diff --git a/base/waitable_event.h b/base/waitable_event.h |
index b72365388334a58111352c7492383e2d3afe636f..84feedc63e9e6834d65991a8709003fd2d3f6582 100644 |
--- a/base/waitable_event.h |
+++ b/base/waitable_event.h |
@@ -8,18 +8,27 @@ |
#include "base/basictypes.h" |
#if defined(OS_WIN) |
-typedef void* HANDLE; |
-#else |
+#include <windows.h> |
+#endif |
+ |
+#if defined(OS_POSIX) |
+#include <list> |
+#include <utility> |
#include "base/condition_variable.h" |
#include "base/lock.h" |
+#include "base/ref_counted.h" |
#endif |
+#include "base/message_loop.h" |
+ |
namespace base { |
class TimeDelta; |
// A WaitableEvent can be a useful thread synchronization tool when you want to |
-// allow one thread to wait for another thread to finish some work. |
+// allow one thread to wait for another thread to finish some work. For |
+// non-Windows systems, this can only be used from within a single address |
+// space. |
// |
// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to |
// protect a simple boolean value. However, if you find yourself using a |
@@ -31,7 +40,6 @@ class TimeDelta; |
// by a Windows event object. This is intentional. If you are writing Windows |
// specific code and you need other features of a Windows event, then you might |
// be better off just using an Windows event directly. |
-// |
class WaitableEvent { |
public: |
// If manual_reset is true, then to set the event state to non-signaled, a |
@@ -40,6 +48,13 @@ class WaitableEvent { |
// waiting thread has been released. |
WaitableEvent(bool manual_reset, bool initially_signaled); |
+#if defined(OS_WIN) |
+ // Create a WaitableEvent from an Event HANDLE which has already been |
+ // created. This objects takes ownership of the HANDLE and will close it when |
+ // deleted. |
+ explicit WaitableEvent(HANDLE event_handle); |
+#endif |
+ |
// WARNING: Destroying a WaitableEvent while threads are waiting on it is not |
// supported. Doing so will cause crashes or other instability. |
~WaitableEvent(); |
@@ -64,14 +79,70 @@ class WaitableEvent { |
// does not necessarily mean that max_time was exceeded. |
bool TimedWait(const TimeDelta& max_time); |
+#if defined(OS_WIN) |
+ HANDLE handle() const { return handle_; } |
+#endif |
+ |
+ // Wait, synchronously, on multiple events. |
+ // waitables: an array of WaitableEvent pointers |
+ // count: the number of elements in @waitables |
+ // |
+ // returns: the index of a WaitableEvent which has been signaled. |
+ static size_t WaitMany(WaitableEvent** waitables, size_t count); |
+ |
+ // For asynchronous waiting, see WaitableEventWatcher |
+ |
+ // This is a private helper class. It's here because it's used by friends of |
+ // this class (such as WaitableEventWatcher) to be able to enqueue elements |
+ // of the wait-list |
+ class Waiter { |
+ public: |
+ // Signal the waiter to wake up. |
+ // |
+ // Consider the case of a Waiter which is in multiple WaitableEvent's |
+ // wait-lists. Each WaitableEvent is automatic-reset and two of them are |
+ // signaled at the same time. Now, each will wake only the first waiter in |
+ // the wake-list before resetting. However, if those two waiters happen to |
+ // be the same object (as can happen if another thread didn't have a chance |
+ // to dequeue the waiter from the other wait-list in time), two auto-resets |
+ // will have happened, but only one waiter has been signaled! |
+ // |
+ // Because of this, a Waiter may "reject" a wake by returning false. In |
+ // this case, the auto-reset WaitableEvent shouldn't act as if anything has |
+ // been notified. |
+ virtual bool Fire(WaitableEvent* signaling_event) = 0; |
+ |
+ // Waiters may implement this in order to provide an extra condition for |
+ // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the |
+ // pointers match then this function is called as a final check. See the |
+ // comments in ~Handle for why. |
+ virtual bool Compare(void* tag) = 0; |
+ }; |
+ |
private: |
+ friend class WaitableEventWatcher; |
+ |
#if defined(OS_WIN) |
- HANDLE event_; |
+ HANDLE handle_; |
#else |
- Lock lock_; // Needs to be listed first so it will be constructed first. |
- ConditionVariable cvar_; |
+ bool SignalAll(); |
+ bool SignalOne(); |
+ void Enqueue(Waiter* waiter); |
+ bool Dequeue(Waiter* waiter, void* tag); |
+ |
+ // When dealing with arrays of WaitableEvent*, we want to sort by the address |
+ // of the WaitableEvent in order to have a globally consistent locking order. |
+ // In that case we keep them, in sorted order, in an array of pairs where the |
+ // second element is the index of the WaitableEvent in the original, |
+ // unsorted, array. |
+ typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex; |
+ static unsigned EnqueueMany(WaiterAndIndex* waitables, |
+ size_t count, Waiter* waiter); |
+ |
+ Lock lock_; |
bool signaled_; |
- bool manual_reset_; |
+ const bool manual_reset_; |
+ std::list<Waiter*> waiters_; |
#endif |
DISALLOW_COPY_AND_ASSIGN(WaitableEvent); |