Index: base/synchronization/waitable_event_posix.cc |
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc |
index fccba9d31c67c767b0b8172e10ad127ab2a5cb24..89f42fff2f7d6f9a84d6be5d3923bdc169d5756f 100644 |
--- a/base/synchronization/waitable_event_posix.cc |
+++ b/base/synchronization/waitable_event_posix.cc |
@@ -197,6 +197,11 @@ bool WaitableEvent::TimedWait(const TimeDelta& max_time) { |
sw.Disable(); |
sw.lock()->Release(); |
+ // This is a bug that has been enshrined in the interface of |
+ // WaitableEvent now: |Dequeue| is called even when |sw.fired()| is true, |
+ // even though it'll always return false in that case. However, taking |
+ // the lock ensures that |Signal| has completed before we return and |
+ // means that a WaitableEvent can synchronise its own destruction. |
kernel_->lock_.Acquire(); |
kernel_->Dequeue(&sw, &sw); |
kernel_->lock_.Release(); |
@@ -290,6 +295,11 @@ size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, |
raw_waitables[i]->kernel_->Dequeue(&sw, &sw); |
raw_waitables[i]->kernel_->lock_.Release(); |
} else { |
+ // By taking this lock here we ensure that |Signal| has completed by the |
+ // time we return, because |Signal| holds this lock. This matches the |
+ // behaviour of |Wait| and |TimedWait|. |
+ raw_waitables[i]->kernel_->lock_.Acquire(); |
+ raw_waitables[i]->kernel_->lock_.Release(); |
signaled_index = i; |
} |
} |