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

Unified Diff: base/synchronization/waitable_event_posix.cc

Issue 2758853002: Ensure consistent return ordering in base::WaitableEvent::WaitMany (Closed)
Patch Set: rebase Created 3 years, 9 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/synchronization/waitable_event.h ('k') | base/synchronization/waitable_event_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
// -----------------------------------------------------------------------------
« no previous file with comments | « base/synchronization/waitable_event.h ('k') | base/synchronization/waitable_event_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698