| 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);
|
|
|