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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits>
8 #include <vector> 9 #include <vector>
9 10
10 #include "base/debug/activity_tracker.h" 11 #include "base/debug/activity_tracker.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/synchronization/condition_variable.h" 13 #include "base/synchronization/condition_variable.h"
13 #include "base/synchronization/lock.h" 14 #include "base/synchronization/lock.h"
14 #include "base/synchronization/waitable_event.h" 15 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread_restrictions.h" 16 #include "base/threading/thread_restrictions.h"
16 17
17 // ----------------------------------------------------------------------------- 18 // -----------------------------------------------------------------------------
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 // The set of waitables must be distinct. Since we have just sorted by 260 // The set of waitables must be distinct. Since we have just sorted by
260 // address, we can check this cheaply by comparing pairs of consecutive 261 // address, we can check this cheaply by comparing pairs of consecutive
261 // elements. 262 // elements.
262 for (size_t i = 0; i < waitables.size() - 1; ++i) { 263 for (size_t i = 0; i < waitables.size() - 1; ++i) {
263 DCHECK(waitables[i].first != waitables[i+1].first); 264 DCHECK(waitables[i].first != waitables[i+1].first);
264 } 265 }
265 266
266 SyncWaiter sw; 267 SyncWaiter sw;
267 268
268 const size_t r = EnqueueMany(&waitables[0], count, &sw); 269 const size_t r = EnqueueMany(&waitables[0], count, &sw);
269 if (r) { 270 if (r < count) {
270 // One of the events is already signaled. The SyncWaiter has not been 271 // One of the events is already signaled. The SyncWaiter has not been
271 // enqueued anywhere. EnqueueMany returns the count of remaining waitables 272 // enqueued anywhere.
272 // when the signaled one was seen, so the index of the signaled event is 273 return waitables[r].second;
273 // @count - @r.
274 return waitables[count - r].second;
275 } 274 }
276 275
277 // At this point, we hold the locks on all the WaitableEvents and we have 276 // At this point, we hold the locks on all the WaitableEvents and we have
278 // enqueued our waiter in them all. 277 // enqueued our waiter in them all.
279 sw.lock()->Acquire(); 278 sw.lock()->Acquire();
280 // Release the WaitableEvent locks in the reverse order 279 // Release the WaitableEvent locks in the reverse order
281 for (size_t i = 0; i < count; ++i) { 280 for (size_t i = 0; i < count; ++i) {
282 waitables[count - (1 + i)].first->kernel_->lock_.Release(); 281 waitables[count - (1 + i)].first->kernel_->lock_.Release();
283 } 282 }
284 283
(...skipping 27 matching lines...) Expand all
312 raw_waitables[i]->kernel_->lock_.Acquire(); 311 raw_waitables[i]->kernel_->lock_.Acquire();
313 raw_waitables[i]->kernel_->lock_.Release(); 312 raw_waitables[i]->kernel_->lock_.Release();
314 signaled_index = i; 313 signaled_index = i;
315 } 314 }
316 } 315 }
317 316
318 return signaled_index; 317 return signaled_index;
319 } 318 }
320 319
321 // ----------------------------------------------------------------------------- 320 // -----------------------------------------------------------------------------
322 // If return value == 0: 321 // If return value == count:
323 // The locks of the WaitableEvents have been taken in order and the Waiter has 322 // The locks of the WaitableEvents have been taken in order and the Waiter has
324 // been enqueued in the wait-list of each. None of the WaitableEvents are 323 // been enqueued in the wait-list of each. None of the WaitableEvents are
325 // currently signaled 324 // currently signaled
326 // else: 325 // else:
327 // None of the WaitableEvent locks are held. The Waiter has not been enqueued 326 // None of the WaitableEvent locks are held. The Waiter has not been enqueued
328 // in any of them and the return value is the index of the first WaitableEvent 327 // in any of them and the return value is the index of the WaitableEvent which
329 // which was signaled, from the end of the array. 328 // was signaled with the lowest input index from the original WaitMany call.
330 // ----------------------------------------------------------------------------- 329 // -----------------------------------------------------------------------------
331 // static 330 // static
332 size_t WaitableEvent::EnqueueMany 331 size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables,
333 (std::pair<WaitableEvent*, size_t>* waitables, 332 size_t count,
334 size_t count, Waiter* waiter) { 333 Waiter* waiter) {
335 if (!count) 334 size_t winner = count;
336 return 0; 335 size_t winner_index = count;
336 for (size_t i = 0; i < count; ++i) {
337 auto& kernel = waitables[i].first->kernel_;
338 kernel->lock_.Acquire();
339 if (kernel->signaled_ && waitables[i].second < winner) {
340 winner = waitables[i].second;
341 winner_index = i;
342 }
343 }
337 344
338 waitables[0].first->kernel_->lock_.Acquire(); 345 // No events signaled. All locks acquired. Enqueue the Waiter on all of them
339 if (waitables[0].first->kernel_->signaled_) { 346 // and return.
340 if (!waitables[0].first->kernel_->manual_reset_) 347 if (winner == count) {
341 waitables[0].first->kernel_->signaled_ = false; 348 for (size_t i = 0; i < count; ++i)
342 waitables[0].first->kernel_->lock_.Release(); 349 waitables[i].first->Enqueue(waiter);
343 return count; 350 return count;
351 }
352
353 // Unlock in reverse order and possibly clear the chosen winner's signal
354 // before returning its index.
355 DCHECK_GE(count, 1u);
356 DCHECK_LE(count, static_cast<size_t>(std::numeric_limits<int>::max()));
357 for (int i = static_cast<int>(count - 1); i >= 0; --i) {
dcheng 2017/03/17 22:53:47 One alternative that doesn't require DCHECKing and
Ken Rockot(use gerrit already) 2017/03/18 00:05:25 Oh right, of course. Done.
358 auto& kernel = waitables[i].first->kernel_;
359 if (waitables[i].second == winner) {
360 if (!kernel->manual_reset_)
361 kernel->signaled_ = false;
344 } 362 }
363 kernel->lock_.Release();
364 }
345 365
346 const size_t r = EnqueueMany(waitables + 1, count - 1, waiter); 366 return winner_index;
347 if (r) {
348 waitables[0].first->kernel_->lock_.Release();
349 } else {
350 waitables[0].first->Enqueue(waiter);
351 }
352
353 return r;
354 } 367 }
355 368
356 // ----------------------------------------------------------------------------- 369 // -----------------------------------------------------------------------------
357 370
358 371
359 // ----------------------------------------------------------------------------- 372 // -----------------------------------------------------------------------------
360 // Private functions... 373 // Private functions...
361 374
362 WaitableEvent::WaitableEventKernel::WaitableEventKernel( 375 WaitableEvent::WaitableEventKernel::WaitableEventKernel(
363 ResetPolicy reset_policy, 376 ResetPolicy reset_policy,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 return true; 431 return true;
419 } 432 }
420 } 433 }
421 434
422 return false; 435 return false;
423 } 436 }
424 437
425 // ----------------------------------------------------------------------------- 438 // -----------------------------------------------------------------------------
426 439
427 } // namespace base 440 } // namespace base
OLDNEW
« 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