pthread_waiter.cc 5.0 KB

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