Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Thomas Sepez | 852f156 | 2024-08-19 18:40:41 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. |
| 7 | #pragma allow_unsafe_buffers |
| 8 | #endif |
| 9 | |
[email protected] | 44f9c95 | 2011-01-02 06:05:39 | [diff] [blame] | 10 | #include "base/synchronization/waitable_event.h" |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 11 | |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 12 | #include <windows.h> |
Bruce Dawson | a1e1cfcb | 2022-11-22 20:04:35 | [diff] [blame] | 13 | |
Takuto Ikuta | c8d6b16f | 2024-04-15 16:59:19 | [diff] [blame] | 14 | #include <stddef.h> |
| 15 | |
stanisc | acf6801 | 2016-11-30 19:56:09 | [diff] [blame] | 16 | #include <algorithm> |
Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 17 | #include <optional> |
dcheng | 70c4942 | 2016-03-02 23:20:34 | [diff] [blame] | 18 | #include <utility> |
| 19 | |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 20 | #include "base/compiler_specific.h" |
Chris Davis | 5ed388c | 2024-10-22 21:43:37 | [diff] [blame] | 21 | #include "base/debug/crash_logging.h" |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 22 | #include "base/debug/dump_without_crashing.h" |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 23 | #include "base/logging.h" |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 24 | #include "base/notreached.h" |
rvargas | b2e1b3c | 2015-03-31 03:17:04 | [diff] [blame] | 25 | #include "base/numerics/safe_conversions.h" |
Francois Doray | 3abc0c0 | 2017-09-11 19:53:29 | [diff] [blame] | 26 | #include "base/threading/scoped_blocking_call.h" |
[email protected] | 3a7b66d | 2012-04-26 16:34:16 | [diff] [blame] | 27 | #include "base/threading/thread_restrictions.h" |
[email protected] | 8f9a3a5 | 2013-06-28 15:14:18 | [diff] [blame] | 28 | #include "base/time/time.h" |
Gabriel Charette | ef6cbc2 | 2019-08-02 06:24:59 | [diff] [blame] | 29 | #include "base/time/time_override.h" |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 30 | |
| 31 | namespace base { |
| 32 | |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 33 | namespace { |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 34 | |
| 35 | [[nodiscard]] debug::ScopedCrashKeyString SetLastErrorCrashKey( |
| 36 | DWORD last_error) { |
| 37 | static auto* const key = debug::AllocateCrashKeyString( |
| 38 | "WaitableEvent-last_error", debug::CrashKeySize::Size32); |
| 39 | return debug::ScopedCrashKeyString(key, NumberToString(last_error)); |
| 40 | } |
| 41 | |
| 42 | NOINLINE void ReportInvalidWaitableEventResult(DWORD result, DWORD last_error) { |
| 43 | SCOPED_CRASH_KEY_NUMBER("WaitableEvent", "result", result); |
| 44 | debug::ScopedCrashKeyString last_error_key = SetLastErrorCrashKey(last_error); |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 45 | base::debug::DumpWithoutCrashing(); // https://crbug.com/1478972. |
| 46 | } |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 47 | |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 48 | } // namespace |
| 49 | |
gab | e5ff4d6 | 2016-06-01 00:16:50 | [diff] [blame] | 50 | WaitableEvent::WaitableEvent(ResetPolicy reset_policy, |
| 51 | InitialState initial_state) |
gab | d9aa1d1 | 2016-06-09 18:41:22 | [diff] [blame] | 52 | : handle_(CreateEvent(nullptr, |
| 53 | reset_policy == ResetPolicy::MANUAL, |
| 54 | initial_state == InitialState::SIGNALED, |
| 55 | nullptr)) { |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 56 | // We're probably going to crash anyways if this is ever NULL, so we might as |
| 57 | // well make our stack reports more informative by crashing here. |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 58 | CHECK(handle_.is_valid()); |
[email protected] | 1c4947f | 2009-01-15 22:25:11 | [diff] [blame] | 59 | } |
| 60 | |
rvargas | 94ed6c4e | 2014-11-25 01:23:31 | [diff] [blame] | 61 | WaitableEvent::WaitableEvent(win::ScopedHandle handle) |
dcheng | 70c4942 | 2016-03-02 23:20:34 | [diff] [blame] | 62 | : handle_(std::move(handle)) { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 63 | CHECK(handle_.is_valid()) << "Tried to create WaitableEvent from NULL handle"; |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 64 | } |
| 65 | |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 66 | void WaitableEvent::Reset() { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 67 | ResetEvent(handle_.get()); |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 68 | } |
| 69 | |
Gabriel Charette | ecba93c | 2022-10-31 14:30:55 | [diff] [blame] | 70 | void WaitableEvent::SignalImpl() { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 71 | SetEvent(handle_.get()); |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 72 | } |
| 73 | |
Bartek Nowierski | fa70c22 | 2024-07-01 04:02:08 | [diff] [blame] | 74 | bool WaitableEvent::IsSignaled() const { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 75 | DWORD result = WaitForSingleObject(handle_.get(), 0); |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 76 | if (result != WAIT_OBJECT_0 && result != WAIT_TIMEOUT) { |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 77 | ReportInvalidWaitableEventResult(result, ::GetLastError()); |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 78 | } |
stanisc | acf6801 | 2016-11-30 19:56:09 | [diff] [blame] | 79 | return result == WAIT_OBJECT_0; |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 80 | } |
| 81 | |
Gabriel Charette | ecba93c | 2022-10-31 14:30:55 | [diff] [blame] | 82 | bool WaitableEvent::TimedWaitImpl(TimeDelta wait_delta) { |
Gabriel Charette | c2b3ac89 | 2019-07-30 12:13:47 | [diff] [blame] | 83 | // TimeTicks takes care of overflow but we special case is_max() nonetheless |
Gabriel Charette | ef6cbc2 | 2019-08-02 06:24:59 | [diff] [blame] | 84 | // to avoid invoking TimeTicksNowIgnoringOverride() unnecessarily. |
Gabriel Charette | c2b3ac89 | 2019-07-30 12:13:47 | [diff] [blame] | 85 | // WaitForSingleObject(handle_.Get(), INFINITE) doesn't spuriously wakeup so |
| 86 | // we don't need to worry about is_max() for the increment phase of the loop. |
| 87 | const TimeTicks end_time = |
Gabriel Charette | ef6cbc2 | 2019-08-02 06:24:59 | [diff] [blame] | 88 | wait_delta.is_max() ? TimeTicks::Max() |
| 89 | : subtle::TimeTicksNowIgnoringOverride() + wait_delta; |
Xiaohan Wang | abff030 | 2021-10-27 00:42:57 | [diff] [blame] | 90 | for (TimeDelta remaining = wait_delta; remaining.is_positive(); |
Gabriel Charette | ef6cbc2 | 2019-08-02 06:24:59 | [diff] [blame] | 91 | remaining = end_time - subtle::TimeTicksNowIgnoringOverride()) { |
Gabriel Charette | c2b3ac89 | 2019-07-30 12:13:47 | [diff] [blame] | 92 | // Truncate the timeout to milliseconds, rounded up to avoid spinning |
| 93 | // (either by returning too early or because a < 1ms timeout on Windows |
| 94 | // tends to return immediately). |
| 95 | const DWORD timeout_ms = |
| 96 | remaining.is_max() |
| 97 | ? INFINITE |
| 98 | : saturated_cast<DWORD>(remaining.InMillisecondsRoundedUp()); |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 99 | const DWORD result = WaitForSingleObject(handle_.get(), timeout_ms); |
Etienne Bergeron | d2c6ab9 | 2024-01-25 21:16:34 | [diff] [blame] | 100 | if (result == WAIT_OBJECT_0) { |
| 101 | // The object is signaled. |
| 102 | return true; |
| 103 | } |
| 104 | |
| 105 | if (result == WAIT_TIMEOUT) { |
| 106 | // TimedWait can time out earlier than the specified |timeout| on |
| 107 | // Windows. To make this consistent with the posix implementation we |
| 108 | // should guarantee that TimedWait doesn't return earlier than the |
| 109 | // specified |max_time| and wait again for the remaining time. |
| 110 | continue; |
| 111 | } |
| 112 | |
Chris Davis | 2bc7964 | 2024-10-24 16:01:29 | [diff] [blame] | 113 | // Failures are likely due to ERROR_INVALID_HANDLE. This unrecoverable |
| 114 | // error likely means that the waited-on object has been closed elsewhere, |
| 115 | // possibly due to a double-close on an unrelated HANDLE. Crash |
| 116 | // immediately since it is not possible to reason about the state of the |
| 117 | // process in this case. |
| 118 | if (result == WAIT_FAILED) { |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 119 | debug::ScopedCrashKeyString last_error_key = |
| 120 | SetLastErrorCrashKey(::GetLastError()); |
| 121 | NOTREACHED(); |
Chris Davis | 2bc7964 | 2024-10-24 16:01:29 | [diff] [blame] | 122 | } |
Chris Davis | 5ed388c | 2024-10-22 21:43:37 | [diff] [blame] | 123 | |
Chris Davis | 2bc7964 | 2024-10-24 16:01:29 | [diff] [blame] | 124 | if (wait_delta.is_max()) { |
Chris Davis | 5ed388c | 2024-10-22 21:43:37 | [diff] [blame] | 125 | // The only other documented result value is `WAIT_ABANDONED`. This nor |
| 126 | // any other result should ever be emitted. |
Peter Boström | e1098ef | 2024-10-28 09:04:20 | [diff] [blame] | 127 | ReportInvalidWaitableEventResult(result, ::GetLastError()); |
stanisc | acf6801 | 2016-11-30 19:56:09 | [diff] [blame] | 128 | } |
Gabriel Charette | c2b3ac89 | 2019-07-30 12:13:47 | [diff] [blame] | 129 | } |
stanisc | acf6801 | 2016-11-30 19:56:09 | [diff] [blame] | 130 | return false; |
| 131 | } |
| 132 | |
[email protected] | 1c4947f | 2009-01-15 22:25:11 | [diff] [blame] | 133 | // static |
Thomas Sepez | 852f156 | 2024-08-19 18:40:41 | [diff] [blame] | 134 | size_t WaitableEvent::WaitManyImpl(WaitableEvent** events, size_t count) { |
| 135 | HANDLE handles[MAXIMUM_WAIT_OBJECTS]; |
| 136 | CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS)) |
[email protected] | 1c4947f | 2009-01-15 22:25:11 | [diff] [blame] | 137 | << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; |
| 138 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 139 | for (size_t i = 0; i < count; ++i) { |
Thomas Sepez | 852f156 | 2024-08-19 18:40:41 | [diff] [blame] | 140 | handles[i] = events[i]->handle(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 141 | } |
[email protected] | 1c4947f | 2009-01-15 22:25:11 | [diff] [blame] | 142 | |
Thomas Sepez | 852f156 | 2024-08-19 18:40:41 | [diff] [blame] | 143 | // The cast is safe because count is small - see the CHECK above. |
| 144 | DWORD result = |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 145 | WaitForMultipleObjects(static_cast<DWORD>(count), handles, |
Thomas Sepez | 852f156 | 2024-08-19 18:40:41 | [diff] [blame] | 146 | FALSE, // don't wait for all the objects |
| 147 | INFINITE); // no timeout |
| 148 | if (result >= WAIT_OBJECT_0 + count) { |
[email protected] | ad8cfa9 | 2014-05-21 20:06:23 | [diff] [blame] | 149 | DPLOG(FATAL) << "WaitForMultipleObjects failed"; |
[email protected] | 1c4947f | 2009-01-15 22:25:11 | [diff] [blame] | 150 | return 0; |
| 151 | } |
| 152 | |
| 153 | return result - WAIT_OBJECT_0; |
| 154 | } |
| 155 | |
[email protected] | b2e9729 | 2008-09-02 18:20:34 | [diff] [blame] | 156 | } // namespace base |