tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

win32_waiter.cc (4847B)


      1 // Copyright 2023 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/synchronization/internal/win32_waiter.h"
     16 
     17 #ifdef ABSL_INTERNAL_HAVE_WIN32_WAITER
     18 
     19 #include <windows.h>
     20 
     21 #include "absl/base/config.h"
     22 #include "absl/base/internal/raw_logging.h"
     23 #include "absl/base/internal/thread_identity.h"
     24 #include "absl/base/optimization.h"
     25 #include "absl/synchronization/internal/kernel_timeout.h"
     26 
     27 namespace absl {
     28 ABSL_NAMESPACE_BEGIN
     29 namespace synchronization_internal {
     30 
     31 class Win32Waiter::WinHelper {
     32 public:
     33  static SRWLOCK *GetLock(Win32Waiter *w) {
     34    return reinterpret_cast<SRWLOCK *>(&w->mu_storage_);
     35  }
     36 
     37  static CONDITION_VARIABLE *GetCond(Win32Waiter *w) {
     38    return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_);
     39  }
     40 
     41  static_assert(sizeof(SRWLOCK) == sizeof(void *),
     42                "`mu_storage_` does not have the same size as SRWLOCK");
     43  static_assert(alignof(SRWLOCK) == alignof(void *),
     44                "`mu_storage_` does not have the same alignment as SRWLOCK");
     45 
     46  static_assert(sizeof(CONDITION_VARIABLE) == sizeof(void *),
     47                "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
     48                "as `CONDITION_VARIABLE`");
     49  static_assert(
     50      alignof(CONDITION_VARIABLE) == alignof(void *),
     51      "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
     52 
     53  // The SRWLOCK and CONDITION_VARIABLE types must be trivially constructible
     54  // and destructible because we never call their constructors or destructors.
     55  static_assert(std::is_trivially_constructible<SRWLOCK>::value,
     56                "The `SRWLOCK` type must be trivially constructible");
     57  static_assert(
     58      std::is_trivially_constructible<CONDITION_VARIABLE>::value,
     59      "The `CONDITION_VARIABLE` type must be trivially constructible");
     60  static_assert(std::is_trivially_destructible<SRWLOCK>::value,
     61                "The `SRWLOCK` type must be trivially destructible");
     62  static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value,
     63                "The `CONDITION_VARIABLE` type must be trivially destructible");
     64 };
     65 
     66 class LockHolder {
     67 public:
     68  explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
     69    AcquireSRWLockExclusive(mu_);
     70  }
     71 
     72  LockHolder(const LockHolder&) = delete;
     73  LockHolder& operator=(const LockHolder&) = delete;
     74 
     75  ~LockHolder() {
     76    ReleaseSRWLockExclusive(mu_);
     77  }
     78 
     79 private:
     80  SRWLOCK* mu_;
     81 };
     82 
     83 Win32Waiter::Win32Waiter() {
     84  auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
     85  auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
     86  InitializeSRWLock(mu);
     87  InitializeConditionVariable(cv);
     88  waiter_count_ = 0;
     89  wakeup_count_ = 0;
     90 }
     91 
     92 bool Win32Waiter::Wait(KernelTimeout t) {
     93  SRWLOCK *mu = WinHelper::GetLock(this);
     94  CONDITION_VARIABLE *cv = WinHelper::GetCond(this);
     95 
     96  LockHolder h(mu);
     97  ++waiter_count_;
     98 
     99  // Loop until we find a wakeup to consume or timeout.
    100  // Note that, since the thread ticker is just reset, we don't need to check
    101  // whether the thread is idle on the very first pass of the loop.
    102  bool first_pass = true;
    103  while (wakeup_count_ == 0) {
    104    if (!first_pass) MaybeBecomeIdle();
    105    // No wakeups available, time to wait.
    106    if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
    107      // GetLastError() returns a Win32 DWORD, but we assign to
    108      // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
    109      // initialization guarantees this is not a narrowing conversion.
    110      const unsigned long err{GetLastError()};  // NOLINT(runtime/int)
    111      if (err == ERROR_TIMEOUT) {
    112        --waiter_count_;
    113        return false;
    114      } else {
    115        ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
    116      }
    117    }
    118    first_pass = false;
    119  }
    120  // Consume a wakeup and we're done.
    121  --wakeup_count_;
    122  --waiter_count_;
    123  return true;
    124 }
    125 
    126 void Win32Waiter::Post() {
    127  LockHolder h(WinHelper::GetLock(this));
    128  ++wakeup_count_;
    129  InternalCondVarPoke();
    130 }
    131 
    132 void Win32Waiter::Poke() {
    133  LockHolder h(WinHelper::GetLock(this));
    134  InternalCondVarPoke();
    135 }
    136 
    137 void Win32Waiter::InternalCondVarPoke() {
    138  if (waiter_count_ != 0) {
    139    WakeConditionVariable(WinHelper::GetCond(this));
    140  }
    141 }
    142 
    143 }  // namespace synchronization_internal
    144 ABSL_NAMESPACE_END
    145 }  // namespace absl
    146 
    147 #endif  // ABSL_INTERNAL_HAVE_WIN32_WAITER