tor-browser

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

pthread_waiter.cc (4926B)


      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/pthread_waiter.h"
     16 
     17 #ifdef ABSL_INTERNAL_HAVE_PTHREAD_WAITER
     18 
     19 #include <pthread.h>
     20 #include <sys/time.h>
     21 #include <unistd.h>
     22 
     23 #include <cassert>
     24 #include <cerrno>
     25 
     26 #include "absl/base/config.h"
     27 #include "absl/base/internal/raw_logging.h"
     28 #include "absl/base/internal/thread_identity.h"
     29 #include "absl/base/optimization.h"
     30 #include "absl/synchronization/internal/kernel_timeout.h"
     31 
     32 namespace absl {
     33 ABSL_NAMESPACE_BEGIN
     34 namespace synchronization_internal {
     35 
     36 namespace {
     37 class PthreadMutexHolder {
     38 public:
     39  explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
     40    const int err = pthread_mutex_lock(mu_);
     41    if (err != 0) {
     42      ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
     43    }
     44  }
     45 
     46  PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
     47  PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
     48 
     49  ~PthreadMutexHolder() {
     50    const int err = pthread_mutex_unlock(mu_);
     51    if (err != 0) {
     52      ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
     53    }
     54  }
     55 
     56 private:
     57  pthread_mutex_t *mu_;
     58 };
     59 }  // namespace
     60 
     61 PthreadWaiter::PthreadWaiter() : waiter_count_(0), wakeup_count_(0) {
     62  const int err = pthread_mutex_init(&mu_, 0);
     63  if (err != 0) {
     64    ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
     65  }
     66 
     67  const int err2 = pthread_cond_init(&cv_, 0);
     68  if (err2 != 0) {
     69    ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
     70  }
     71 }
     72 
     73 #ifdef __APPLE__
     74 #define ABSL_INTERNAL_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
     75 #endif
     76 
     77 #if defined(__GLIBC__) && \
     78    (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30))
     79 #define ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT 1
     80 #elif defined(__ANDROID_API__) && __ANDROID_API__ >= 30
     81 #define ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT 1
     82 #endif
     83 
     84 // Calls pthread_cond_timedwait() or possibly something else like
     85 // pthread_cond_timedwait_relative_np() depending on the platform and
     86 // KernelTimeout requested. The return value is the same as the return
     87 // value of pthread_cond_timedwait().
     88 int PthreadWaiter::TimedWait(KernelTimeout t) {
     89  assert(t.has_timeout());
     90  if (KernelTimeout::SupportsSteadyClock() && t.is_relative_timeout()) {
     91 #ifdef ABSL_INTERNAL_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
     92    const auto rel_timeout = t.MakeRelativeTimespec();
     93    return pthread_cond_timedwait_relative_np(&cv_, &mu_, &rel_timeout);
     94 #elif defined(ABSL_INTERNAL_HAVE_PTHREAD_COND_CLOCKWAIT) && \
     95    defined(CLOCK_MONOTONIC)
     96    const auto abs_clock_timeout = t.MakeClockAbsoluteTimespec(CLOCK_MONOTONIC);
     97    return pthread_cond_clockwait(&cv_, &mu_, CLOCK_MONOTONIC,
     98                                  &abs_clock_timeout);
     99 #endif
    100  }
    101 
    102  const auto abs_timeout = t.MakeAbsTimespec();
    103  return pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
    104 }
    105 
    106 bool PthreadWaiter::Wait(KernelTimeout t) {
    107  PthreadMutexHolder h(&mu_);
    108  ++waiter_count_;
    109  // Loop until we find a wakeup to consume or timeout.
    110  // Note that, since the thread ticker is just reset, we don't need to check
    111  // whether the thread is idle on the very first pass of the loop.
    112  bool first_pass = true;
    113  while (wakeup_count_ == 0) {
    114    if (!first_pass) MaybeBecomeIdle();
    115    // No wakeups available, time to wait.
    116    if (!t.has_timeout()) {
    117      const int err = pthread_cond_wait(&cv_, &mu_);
    118      if (err != 0) {
    119        ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
    120      }
    121    } else {
    122      const int err = TimedWait(t);
    123      if (err == ETIMEDOUT) {
    124        --waiter_count_;
    125        return false;
    126      }
    127      if (err != 0) {
    128        ABSL_RAW_LOG(FATAL, "PthreadWaiter::TimedWait() failed: %d", err);
    129      }
    130    }
    131    first_pass = false;
    132  }
    133  // Consume a wakeup and we're done.
    134  --wakeup_count_;
    135  --waiter_count_;
    136  return true;
    137 }
    138 
    139 void PthreadWaiter::Post() {
    140  PthreadMutexHolder h(&mu_);
    141  ++wakeup_count_;
    142  InternalCondVarPoke();
    143 }
    144 
    145 void PthreadWaiter::Poke() {
    146  PthreadMutexHolder h(&mu_);
    147  InternalCondVarPoke();
    148 }
    149 
    150 void PthreadWaiter::InternalCondVarPoke() {
    151  if (waiter_count_ != 0) {
    152    const int err = pthread_cond_signal(&cv_);
    153    if (ABSL_PREDICT_FALSE(err != 0)) {
    154      ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
    155    }
    156  }
    157 }
    158 
    159 }  // namespace synchronization_internal
    160 ABSL_NAMESPACE_END
    161 }  // namespace absl
    162 
    163 #endif  // ABSL_INTERNAL_HAVE_PTHREAD_WAITER