waitable_event_win.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/synchronization/waitable_event.h"
  5. #include <windows.h>
  6. #include <stddef.h>
  7. #include <algorithm>
  8. #include <utility>
  9. #include "base/debug/activity_tracker.h"
  10. #include "base/logging.h"
  11. #include "base/numerics/safe_conversions.h"
  12. #include "base/threading/scoped_blocking_call.h"
  13. #include "base/threading/thread_restrictions.h"
  14. #include "base/time/time.h"
  15. #include "base/time/time_override.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. namespace base {
  18. WaitableEvent::WaitableEvent(ResetPolicy reset_policy,
  19. InitialState initial_state)
  20. : handle_(CreateEvent(nullptr,
  21. reset_policy == ResetPolicy::MANUAL,
  22. initial_state == InitialState::SIGNALED,
  23. nullptr)) {
  24. // We're probably going to crash anyways if this is ever NULL, so we might as
  25. // well make our stack reports more informative by crashing here.
  26. CHECK(handle_.is_valid());
  27. }
  28. WaitableEvent::WaitableEvent(win::ScopedHandle handle)
  29. : handle_(std::move(handle)) {
  30. CHECK(handle_.is_valid()) << "Tried to create WaitableEvent from NULL handle";
  31. }
  32. WaitableEvent::~WaitableEvent() = default;
  33. void WaitableEvent::Reset() {
  34. ResetEvent(handle_.get());
  35. }
  36. void WaitableEvent::Signal() {
  37. SetEvent(handle_.get());
  38. }
  39. bool WaitableEvent::IsSignaled() {
  40. DWORD result = WaitForSingleObject(handle_.get(), 0);
  41. DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
  42. << "Unexpected WaitForSingleObject result " << result;
  43. return result == WAIT_OBJECT_0;
  44. }
  45. void WaitableEvent::Wait() {
  46. // Record the event that this thread is blocking upon (for hang diagnosis) and
  47. // consider it blocked for scheduling purposes. Ignore this for non-blocking
  48. // WaitableEvents.
  49. absl::optional<debug::ScopedEventWaitActivity> event_activity;
  50. absl::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
  51. scoped_blocking_call;
  52. if (waiting_is_blocking_) {
  53. event_activity.emplace(this);
  54. scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
  55. }
  56. DWORD result = WaitForSingleObject(handle_.get(), INFINITE);
  57. // It is most unexpected that this should ever fail. Help consumers learn
  58. // about it if it should ever fail.
  59. DPCHECK(result != WAIT_FAILED);
  60. DCHECK_EQ(WAIT_OBJECT_0, result);
  61. }
  62. bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) {
  63. if (wait_delta <= TimeDelta())
  64. return IsSignaled();
  65. // Record the event that this thread is blocking upon (for hang diagnosis) and
  66. // consider it blocked for scheduling purposes. Ignore this for non-blocking
  67. // WaitableEvents.
  68. absl::optional<debug::ScopedEventWaitActivity> event_activity;
  69. absl::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
  70. scoped_blocking_call;
  71. if (waiting_is_blocking_) {
  72. event_activity.emplace(this);
  73. scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
  74. }
  75. // TimeTicks takes care of overflow but we special case is_max() nonetheless
  76. // to avoid invoking TimeTicksNowIgnoringOverride() unnecessarily.
  77. // WaitForSingleObject(handle_.Get(), INFINITE) doesn't spuriously wakeup so
  78. // we don't need to worry about is_max() for the increment phase of the loop.
  79. const TimeTicks end_time =
  80. wait_delta.is_max() ? TimeTicks::Max()
  81. : subtle::TimeTicksNowIgnoringOverride() + wait_delta;
  82. for (TimeDelta remaining = wait_delta; remaining.is_positive();
  83. remaining = end_time - subtle::TimeTicksNowIgnoringOverride()) {
  84. // Truncate the timeout to milliseconds, rounded up to avoid spinning
  85. // (either by returning too early or because a < 1ms timeout on Windows
  86. // tends to return immediately).
  87. const DWORD timeout_ms =
  88. remaining.is_max()
  89. ? INFINITE
  90. : saturated_cast<DWORD>(remaining.InMillisecondsRoundedUp());
  91. const DWORD result = WaitForSingleObject(handle_.get(), timeout_ms);
  92. DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
  93. << "Unexpected WaitForSingleObject result " << result;
  94. switch (result) {
  95. case WAIT_OBJECT_0:
  96. return true;
  97. case WAIT_TIMEOUT:
  98. // TimedWait can time out earlier than the specified |timeout| on
  99. // Windows. To make this consistent with the posix implementation we
  100. // should guarantee that TimedWait doesn't return earlier than the
  101. // specified |max_time| and wait again for the remaining time.
  102. continue;
  103. }
  104. }
  105. return false;
  106. }
  107. // static
  108. size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
  109. DCHECK(count) << "Cannot wait on no events";
  110. internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
  111. FROM_HERE, BlockingType::MAY_BLOCK);
  112. // Record an event (the first) that this thread is blocking upon.
  113. debug::ScopedEventWaitActivity event_activity(events[0]);
  114. HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  115. CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS))
  116. << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
  117. for (size_t i = 0; i < count; ++i)
  118. handles[i] = events[i]->handle();
  119. // The cast is safe because count is small - see the CHECK above.
  120. DWORD result =
  121. WaitForMultipleObjects(static_cast<DWORD>(count),
  122. handles,
  123. FALSE, // don't wait for all the objects
  124. INFINITE); // no timeout
  125. if (result >= WAIT_OBJECT_0 + count) {
  126. DPLOG(FATAL) << "WaitForMultipleObjects failed";
  127. return 0;
  128. }
  129. return result - WAIT_OBJECT_0;
  130. }
  131. } // namespace base