xref: /aosp_15_r20/external/cronet/base/task/thread_pool/semaphore/semaphore_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 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 // This file is a clone of "v8/src/base/platform/semaphore.cc" in v8.
6 // Keep in sync, especially when fixing bugs.
7 
8 // Copyright 2013 the V8 project authors. All rights reserved.
9 // Use of this source code is governed by a BSD-style license that can be
10 // found in the LICENSE file.
11 
12 #include "base/task/thread_pool/semaphore.h"
13 
14 #include <windows.h>
15 
16 #include "base/check.h"
17 #include "base/time/time.h"
18 
19 namespace base {
20 namespace internal {
21 
Semaphore(int count)22 Semaphore::Semaphore(int count) {
23   CHECK_GE(count, 0);
24   native_handle_ = ::CreateSemaphoreA(
25       nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
26   CHECK(!!native_handle_);
27 }
28 
~Semaphore()29 Semaphore::~Semaphore() {
30   const bool result = CloseHandle(native_handle_);
31   CHECK(result);
32 }
33 
Signal()34 void Semaphore::Signal() {
35   const bool result = ReleaseSemaphore(native_handle_, 1, nullptr);
36   CHECK(result);
37 }
38 
Wait()39 void Semaphore::Wait() {
40   const DWORD result = WaitForSingleObject(native_handle_, INFINITE);
41   CHECK_EQ(result, WAIT_OBJECT_0);
42 }
43 
TimedWait(TimeDelta timeout)44 bool Semaphore::TimedWait(TimeDelta timeout) {
45   const DWORD wait_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
46   const TimeTicks start = TimeTicks::Now();
47   DWORD result;
48   // WaitForSingleObject has been shown to experience spurious wakeups (on the
49   // order of 10ms before when it was supposed to wake up), so retry until at
50   // least |timeout| has passed.
51   do {
52     result = WaitForSingleObject(native_handle_, wait_ms);
53     if (result == WAIT_OBJECT_0) {
54       return true;
55     }
56   } while (TimeTicks::Now() <= start + timeout);
57   CHECK_EQ(result, static_cast<DWORD>(WAIT_TIMEOUT));
58   return false;
59 }
60 
61 }  // namespace internal
62 }  // namespace base
63