Index: base/synchronization/waitable_event_posix.cc |
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc |
index 846fa06700e1dcb1c1c5976eb2397643c0698759..5dfff468ad6acb0f2c81df98bcc31564f7029506 100644 |
--- a/base/synchronization/waitable_event_posix.cc |
+++ b/base/synchronization/waitable_event_posix.cc |
@@ -5,7 +5,6 @@ |
#include <stddef.h> |
#include <algorithm> |
-#include <limits> |
#include <vector> |
#include "base/debug/activity_tracker.h" |
@@ -267,10 +266,12 @@ |
SyncWaiter sw; |
const size_t r = EnqueueMany(&waitables[0], count, &sw); |
- if (r < count) { |
+ if (r) { |
// One of the events is already signaled. The SyncWaiter has not been |
- // enqueued anywhere. |
- return waitables[r].second; |
+ // enqueued anywhere. EnqueueMany returns the count of remaining waitables |
+ // when the signaled one was seen, so the index of the signaled event is |
+ // @count - @r. |
+ return waitables[count - r].second; |
} |
// At this point, we hold the locks on all the WaitableEvents and we have |
@@ -318,50 +319,38 @@ |
} |
// ----------------------------------------------------------------------------- |
-// If return value == count: |
+// If return value == 0: |
// The locks of the WaitableEvents have been taken in order and the Waiter has |
// been enqueued in the wait-list of each. None of the WaitableEvents are |
// currently signaled |
// else: |
// None of the WaitableEvent locks are held. The Waiter has not been enqueued |
-// in any of them and the return value is the index of the WaitableEvent which |
-// was signaled with the lowest input index from the original WaitMany call. |
+// in any of them and the return value is the index of the first WaitableEvent |
+// which was signaled, from the end of the array. |
// ----------------------------------------------------------------------------- |
// static |
-size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables, |
- size_t count, |
- Waiter* waiter) { |
- size_t winner = count; |
- size_t winner_index = count; |
- for (size_t i = 0; i < count; ++i) { |
- auto& kernel = waitables[i].first->kernel_; |
- kernel->lock_.Acquire(); |
- if (kernel->signaled_ && waitables[i].second < winner) { |
- winner = waitables[i].second; |
- winner_index = i; |
- } |
- } |
- |
- // No events signaled. All locks acquired. Enqueue the Waiter on all of them |
- // and return. |
- if (winner == count) { |
- for (size_t i = 0; i < count; ++i) |
- waitables[i].first->Enqueue(waiter); |
- return count; |
- } |
- |
- // Unlock in reverse order and possibly clear the chosen winner's signal |
- // before returning its index. |
- for (auto* w = waitables + count - 1; w >= waitables; --w) { |
- auto& kernel = w->first->kernel_; |
- if (w->second == winner) { |
- if (!kernel->manual_reset_) |
- kernel->signaled_ = false; |
- } |
- kernel->lock_.Release(); |
- } |
- |
- return winner_index; |
+size_t WaitableEvent::EnqueueMany |
+ (std::pair<WaitableEvent*, size_t>* waitables, |
+ size_t count, Waiter* waiter) { |
+ if (!count) |
+ return 0; |
+ |
+ waitables[0].first->kernel_->lock_.Acquire(); |
+ if (waitables[0].first->kernel_->signaled_) { |
+ if (!waitables[0].first->kernel_->manual_reset_) |
+ waitables[0].first->kernel_->signaled_ = false; |
+ waitables[0].first->kernel_->lock_.Release(); |
+ return count; |
+ } |
+ |
+ const size_t r = EnqueueMany(waitables + 1, count - 1, waiter); |
+ if (r) { |
+ waitables[0].first->kernel_->lock_.Release(); |
+ } else { |
+ waitables[0].first->Enqueue(waiter); |
+ } |
+ |
+ return r; |
} |
// ----------------------------------------------------------------------------- |