OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |