Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4395)

Unified Diff: base/waitable_event.h

Issue 16554: WaitableEvent (Closed)
Patch Set: Addresssing darin's comments (round 2) Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/build/base.vcproj ('k') | base/waitable_event_generic.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « base/build/base.vcproj ('k') | base/waitable_event_generic.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698