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