| Index: base/synchronization/waitable_event_posix.cc
|
| diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
|
| index 5dfff468ad6acb0f2c81df98bcc31564f7029506..846fa06700e1dcb1c1c5976eb2397643c0698759 100644
|
| --- a/base/synchronization/waitable_event_posix.cc
|
| +++ b/base/synchronization/waitable_event_posix.cc
|
| @@ -5,6 +5,7 @@
|
| #include <stddef.h>
|
|
|
| #include <algorithm>
|
| +#include <limits>
|
| #include <vector>
|
|
|
| #include "base/debug/activity_tracker.h"
|
| @@ -266,12 +267,10 @@ size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
|
| SyncWaiter sw;
|
|
|
| const size_t r = EnqueueMany(&waitables[0], count, &sw);
|
| - if (r) {
|
| + if (r < count) {
|
| // One of the events is already signaled. The SyncWaiter has not been
|
| - // 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;
|
| + // enqueued anywhere.
|
| + return waitables[r].second;
|
| }
|
|
|
| // At this point, we hold the locks on all the WaitableEvents and we have
|
| @@ -319,38 +318,50 @@ size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
|
| }
|
|
|
| // -----------------------------------------------------------------------------
|
| -// If return value == 0:
|
| +// If return value == count:
|
| // 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 first WaitableEvent
|
| -// which was signaled, from the end of the array.
|
| +// 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.
|
| // -----------------------------------------------------------------------------
|
| // static
|
| -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;
|
| +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;
|
| }
|
| + }
|
|
|
| - const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
|
| - if (r) {
|
| - waitables[0].first->kernel_->lock_.Release();
|
| - } else {
|
| - waitables[0].first->Enqueue(waiter);
|
| + // 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 r;
|
| + return winner_index;
|
| }
|
|
|
| // -----------------------------------------------------------------------------
|
|
|