waiter.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // Copyright 2017 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 "absl/synchronization/internal/waiter.h"
  15. #include "absl/base/config.h"
  16. #ifdef _WIN32
  17. #include <windows.h>
  18. #else
  19. #include <pthread.h>
  20. #include <sys/time.h>
  21. #include <unistd.h>
  22. #endif
  23. #ifdef __linux__
  24. #include <linux/futex.h>
  25. #include <sys/syscall.h>
  26. #endif
  27. #ifdef ABSL_HAVE_SEMAPHORE_H
  28. #include <semaphore.h>
  29. #endif
  30. #include <errno.h>
  31. #include <stdio.h>
  32. #include <time.h>
  33. #include <atomic>
  34. #include <cassert>
  35. #include <cstdint>
  36. #include <new>
  37. #include <type_traits>
  38. #include "absl/base/internal/raw_logging.h"
  39. #include "absl/base/internal/thread_identity.h"
  40. #include "absl/base/optimization.h"
  41. #include "absl/synchronization/internal/kernel_timeout.h"
  42. namespace absl {
  43. ABSL_NAMESPACE_BEGIN
  44. namespace synchronization_internal {
  45. static void MaybeBecomeIdle() {
  46. base_internal::ThreadIdentity *identity =
  47. base_internal::CurrentThreadIdentityIfPresent();
  48. assert(identity != nullptr);
  49. const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
  50. const int ticker = identity->ticker.load(std::memory_order_relaxed);
  51. const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
  52. if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) {
  53. identity->is_idle.store(true, std::memory_order_relaxed);
  54. }
  55. }
  56. #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
  57. Waiter::Waiter() {
  58. futex_.store(0, std::memory_order_relaxed);
  59. }
  60. Waiter::~Waiter() = default;
  61. bool Waiter::Wait(KernelTimeout t) {
  62. // Loop until we can atomically decrement futex from a positive
  63. // value, waiting on a futex while we believe it is zero.
  64. // Note that, since the thread ticker is just reset, we don't need to check
  65. // whether the thread is idle on the very first pass of the loop.
  66. bool first_pass = true;
  67. while (true) {
  68. int32_t x = futex_.load(std::memory_order_relaxed);
  69. while (x != 0) {
  70. if (!futex_.compare_exchange_weak(x, x - 1,
  71. std::memory_order_acquire,
  72. std::memory_order_relaxed)) {
  73. continue; // Raced with someone, retry.
  74. }
  75. return true; // Consumed a wakeup, we are done.
  76. }
  77. if (!first_pass) MaybeBecomeIdle();
  78. const int err = Futex::WaitUntil(&futex_, 0, t);
  79. if (err != 0) {
  80. if (err == -EINTR || err == -EWOULDBLOCK) {
  81. // Do nothing, the loop will retry.
  82. } else if (err == -ETIMEDOUT) {
  83. return false;
  84. } else {
  85. ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
  86. }
  87. }
  88. first_pass = false;
  89. }
  90. }
  91. void Waiter::Post() {
  92. if (futex_.fetch_add(1, std::memory_order_release) == 0) {
  93. // We incremented from 0, need to wake a potential waiter.
  94. Poke();
  95. }
  96. }
  97. void Waiter::Poke() {
  98. // Wake one thread waiting on the futex.
  99. const int err = Futex::Wake(&futex_, 1);
  100. if (ABSL_PREDICT_FALSE(err < 0)) {
  101. ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
  102. }
  103. }
  104. #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
  105. class PthreadMutexHolder {
  106. public:
  107. explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
  108. const int err = pthread_mutex_lock(mu_);
  109. if (err != 0) {
  110. ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
  111. }
  112. }
  113. PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
  114. PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
  115. ~PthreadMutexHolder() {
  116. const int err = pthread_mutex_unlock(mu_);
  117. if (err != 0) {
  118. ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
  119. }
  120. }
  121. private:
  122. pthread_mutex_t *mu_;
  123. };
  124. Waiter::Waiter() {
  125. const int err = pthread_mutex_init(&mu_, 0);
  126. if (err != 0) {
  127. ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
  128. }
  129. const int err2 = pthread_cond_init(&cv_, 0);
  130. if (err2 != 0) {
  131. ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
  132. }
  133. waiter_count_ = 0;
  134. wakeup_count_ = 0;
  135. }
  136. Waiter::~Waiter() {
  137. const int err = pthread_mutex_destroy(&mu_);
  138. if (err != 0) {
  139. ABSL_RAW_LOG(FATAL, "pthread_mutex_destroy failed: %d", err);
  140. }
  141. const int err2 = pthread_cond_destroy(&cv_);
  142. if (err2 != 0) {
  143. ABSL_RAW_LOG(FATAL, "pthread_cond_destroy failed: %d", err2);
  144. }
  145. }
  146. bool Waiter::Wait(KernelTimeout t) {
  147. struct timespec abs_timeout;
  148. if (t.has_timeout()) {
  149. abs_timeout = t.MakeAbsTimespec();
  150. }
  151. PthreadMutexHolder h(&mu_);
  152. ++waiter_count_;
  153. // Loop until we find a wakeup to consume or timeout.
  154. // Note that, since the thread ticker is just reset, we don't need to check
  155. // whether the thread is idle on the very first pass of the loop.
  156. bool first_pass = true;
  157. while (wakeup_count_ == 0) {
  158. if (!first_pass) MaybeBecomeIdle();
  159. // No wakeups available, time to wait.
  160. if (!t.has_timeout()) {
  161. const int err = pthread_cond_wait(&cv_, &mu_);
  162. if (err != 0) {
  163. ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
  164. }
  165. } else {
  166. const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
  167. if (err == ETIMEDOUT) {
  168. --waiter_count_;
  169. return false;
  170. }
  171. if (err != 0) {
  172. ABSL_RAW_LOG(FATAL, "pthread_cond_timedwait failed: %d", err);
  173. }
  174. }
  175. first_pass = false;
  176. }
  177. // Consume a wakeup and we're done.
  178. --wakeup_count_;
  179. --waiter_count_;
  180. return true;
  181. }
  182. void Waiter::Post() {
  183. PthreadMutexHolder h(&mu_);
  184. ++wakeup_count_;
  185. InternalCondVarPoke();
  186. }
  187. void Waiter::Poke() {
  188. PthreadMutexHolder h(&mu_);
  189. InternalCondVarPoke();
  190. }
  191. void Waiter::InternalCondVarPoke() {
  192. if (waiter_count_ != 0) {
  193. const int err = pthread_cond_signal(&cv_);
  194. if (ABSL_PREDICT_FALSE(err != 0)) {
  195. ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
  196. }
  197. }
  198. }
  199. #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
  200. Waiter::Waiter() {
  201. if (sem_init(&sem_, 0, 0) != 0) {
  202. ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
  203. }
  204. wakeups_.store(0, std::memory_order_relaxed);
  205. }
  206. Waiter::~Waiter() {
  207. if (sem_destroy(&sem_) != 0) {
  208. ABSL_RAW_LOG(FATAL, "sem_destroy failed with errno %d\n", errno);
  209. }
  210. }
  211. bool Waiter::Wait(KernelTimeout t) {
  212. struct timespec abs_timeout;
  213. if (t.has_timeout()) {
  214. abs_timeout = t.MakeAbsTimespec();
  215. }
  216. // Loop until we timeout or consume a wakeup.
  217. // Note that, since the thread ticker is just reset, we don't need to check
  218. // whether the thread is idle on the very first pass of the loop.
  219. bool first_pass = true;
  220. while (true) {
  221. int x = wakeups_.load(std::memory_order_relaxed);
  222. while (x != 0) {
  223. if (!wakeups_.compare_exchange_weak(x, x - 1,
  224. std::memory_order_acquire,
  225. std::memory_order_relaxed)) {
  226. continue; // Raced with someone, retry.
  227. }
  228. // Successfully consumed a wakeup, we're done.
  229. return true;
  230. }
  231. if (!first_pass) MaybeBecomeIdle();
  232. // Nothing to consume, wait (looping on EINTR).
  233. while (true) {
  234. if (!t.has_timeout()) {
  235. if (sem_wait(&sem_) == 0) break;
  236. if (errno == EINTR) continue;
  237. ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
  238. } else {
  239. if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
  240. if (errno == EINTR) continue;
  241. if (errno == ETIMEDOUT) return false;
  242. ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
  243. }
  244. }
  245. first_pass = false;
  246. }
  247. }
  248. void Waiter::Post() {
  249. // Post a wakeup.
  250. if (wakeups_.fetch_add(1, std::memory_order_release) == 0) {
  251. // We incremented from 0, need to wake a potential waiter.
  252. Poke();
  253. }
  254. }
  255. void Waiter::Poke() {
  256. if (sem_post(&sem_) != 0) { // Wake any semaphore waiter.
  257. ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno);
  258. }
  259. }
  260. #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
  261. class Waiter::WinHelper {
  262. public:
  263. static SRWLOCK *GetLock(Waiter *w) {
  264. return reinterpret_cast<SRWLOCK *>(&w->mu_storage_);
  265. }
  266. static CONDITION_VARIABLE *GetCond(Waiter *w) {
  267. return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_);
  268. }
  269. static_assert(sizeof(SRWLOCK) == sizeof(void *),
  270. "`mu_storage_` does not have the same size as SRWLOCK");
  271. static_assert(alignof(SRWLOCK) == alignof(void *),
  272. "`mu_storage_` does not have the same alignment as SRWLOCK");
  273. static_assert(sizeof(CONDITION_VARIABLE) == sizeof(void *),
  274. "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
  275. "as `CONDITION_VARIABLE`");
  276. static_assert(
  277. alignof(CONDITION_VARIABLE) == alignof(void *),
  278. "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
  279. // The SRWLOCK and CONDITION_VARIABLE types must be trivially constructible
  280. // and destructible because we never call their constructors or destructors.
  281. static_assert(std::is_trivially_constructible<SRWLOCK>::value,
  282. "The `SRWLOCK` type must be trivially constructible");
  283. static_assert(
  284. std::is_trivially_constructible<CONDITION_VARIABLE>::value,
  285. "The `CONDITION_VARIABLE` type must be trivially constructible");
  286. static_assert(std::is_trivially_destructible<SRWLOCK>::value,
  287. "The `SRWLOCK` type must be trivially destructible");
  288. static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value,
  289. "The `CONDITION_VARIABLE` type must be trivially destructible");
  290. };
  291. class LockHolder {
  292. public:
  293. explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
  294. AcquireSRWLockExclusive(mu_);
  295. }
  296. LockHolder(const LockHolder&) = delete;
  297. LockHolder& operator=(const LockHolder&) = delete;
  298. ~LockHolder() {
  299. ReleaseSRWLockExclusive(mu_);
  300. }
  301. private:
  302. SRWLOCK* mu_;
  303. };
  304. Waiter::Waiter() {
  305. auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
  306. auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
  307. InitializeSRWLock(mu);
  308. InitializeConditionVariable(cv);
  309. waiter_count_ = 0;
  310. wakeup_count_ = 0;
  311. }
  312. // SRW locks and condition variables do not need to be explicitly destroyed.
  313. // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock
  314. // https://stackoverflow.com/questions/28975958/why-does-windows-have-no-deleteconditionvariable-function-to-go-together-with
  315. Waiter::~Waiter() = default;
  316. bool Waiter::Wait(KernelTimeout t) {
  317. SRWLOCK *mu = WinHelper::GetLock(this);
  318. CONDITION_VARIABLE *cv = WinHelper::GetCond(this);
  319. LockHolder h(mu);
  320. ++waiter_count_;
  321. // Loop until we find a wakeup to consume or timeout.
  322. // Note that, since the thread ticker is just reset, we don't need to check
  323. // whether the thread is idle on the very first pass of the loop.
  324. bool first_pass = true;
  325. while (wakeup_count_ == 0) {
  326. if (!first_pass) MaybeBecomeIdle();
  327. // No wakeups available, time to wait.
  328. if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
  329. // GetLastError() returns a Win32 DWORD, but we assign to
  330. // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform
  331. // initialization guarantees this is not a narrowing conversion.
  332. const unsigned long err{GetLastError()}; // NOLINT(runtime/int)
  333. if (err == ERROR_TIMEOUT) {
  334. --waiter_count_;
  335. return false;
  336. } else {
  337. ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
  338. }
  339. }
  340. first_pass = false;
  341. }
  342. // Consume a wakeup and we're done.
  343. --wakeup_count_;
  344. --waiter_count_;
  345. return true;
  346. }
  347. void Waiter::Post() {
  348. LockHolder h(WinHelper::GetLock(this));
  349. ++wakeup_count_;
  350. InternalCondVarPoke();
  351. }
  352. void Waiter::Poke() {
  353. LockHolder h(WinHelper::GetLock(this));
  354. InternalCondVarPoke();
  355. }
  356. void Waiter::InternalCondVarPoke() {
  357. if (waiter_count_ != 0) {
  358. WakeConditionVariable(WinHelper::GetCond(this));
  359. }
  360. }
  361. #else
  362. #error Unknown ABSL_WAITER_MODE
  363. #endif
  364. } // namespace synchronization_internal
  365. ABSL_NAMESPACE_END
  366. } // namespace absl