Index: base/waitable_event.h |
diff --git a/base/waitable_event.h b/base/waitable_event.h |
index 73fc7ff56ed938e1cc6b175e60d4c760dd472fa6..d2b0999db30b1804bac82309f06afca5db0f03b8 100644 |
--- a/base/waitable_event.h |
+++ b/base/waitable_event.h |
@@ -16,6 +16,7 @@ |
#include <utility> |
#include "base/condition_variable.h" |
#include "base/lock.h" |
+#include "base/ref_counted.h" |
#endif |
#include "base/message_loop.h" |
@@ -60,8 +61,6 @@ class WaitableEvent { |
HANDLE Release(); |
#endif |
- // WARNING: Destroying a WaitableEvent while threads are waiting on it is not |
- // supported. Doing so will cause crashes or other instability. |
~WaitableEvent(); |
// Put the event in the un-signaled state. |
@@ -93,6 +92,9 @@ class WaitableEvent { |
// count: the number of elements in @waitables |
// |
// returns: the index of a WaitableEvent which has been signaled. |
+ // |
+ // You MUST NOT delete any of the WaitableEvent objects while this wait is |
+ // happening. |
static size_t WaitMany(WaitableEvent** waitables, size_t count); |
// For asynchronous waiting, see WaitableEventWatcher |
@@ -130,10 +132,35 @@ class WaitableEvent { |
#if defined(OS_WIN) |
HANDLE handle_; |
#else |
+ // On Windows, one can close a HANDLE which is currently being waited on. The |
+ // MSDN documentation says that the resulting behaviour is 'undefined', but |
+ // it doesn't crash. However, if we were to include the following members |
+ // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an |
+ // event which gets deleted. This mismatch has bitten us several times now, |
+ // so we have a kernel of the WaitableEvent, which is reference counted. |
+ // WaitableEventWatchers may then take a reference and thus match the Windows |
+ // behaviour. |
+ struct WaitableEventKernel : |
+ public RefCountedThreadSafe<WaitableEventKernel> { |
+ public: |
+ WaitableEventKernel(bool manual_reset, bool initially_signaled) |
+ : manual_reset_(manual_reset), |
+ signaled_(initially_signaled) { |
+ } |
+ |
+ bool Dequeue(Waiter* waiter, void* tag); |
+ |
+ Lock lock_; |
+ bool signaled_; |
+ const bool manual_reset_; |
+ std::list<Waiter*> waiters_; |
+ }; |
+ |
+ scoped_refptr<WaitableEventKernel> kernel_; |
+ |
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. |
@@ -143,11 +170,6 @@ class WaitableEvent { |
typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex; |
static size_t EnqueueMany(WaiterAndIndex* waitables, |
size_t count, Waiter* waiter); |
- |
- Lock lock_; |
- bool signaled_; |
- const bool manual_reset_; |
- std::list<Waiter*> waiters_; |
#endif |
DISALLOW_COPY_AND_ASSIGN(WaitableEvent); |