Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <atomic>
00020 #include <cstdint>
00021
00022 #include "absl/base/internal/spinlock_wait.h"
00023
00024 #if defined(_WIN32)
00025 #include "absl/base/internal/spinlock_win32.inc"
00026 #elif defined(__linux__)
00027 #include "absl/base/internal/spinlock_linux.inc"
00028 #elif defined(__akaros__)
00029 #include "absl/base/internal/spinlock_akaros.inc"
00030 #else
00031 #include "absl/base/internal/spinlock_posix.inc"
00032 #endif
00033
00034 namespace absl {
00035 namespace base_internal {
00036
00037
00038 uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
00039 const SpinLockWaitTransition trans[],
00040 base_internal::SchedulingMode scheduling_mode) {
00041 int loop = 0;
00042 for (;;) {
00043 uint32_t v = w->load(std::memory_order_acquire);
00044 int i;
00045 for (i = 0; i != n && v != trans[i].from; i++) {
00046 }
00047 if (i == n) {
00048 SpinLockDelay(w, v, ++loop, scheduling_mode);
00049 } else if (trans[i].to == v ||
00050 w->compare_exchange_strong(v, trans[i].to,
00051 std::memory_order_acquire,
00052 std::memory_order_relaxed)) {
00053 if (trans[i].done) return v;
00054 }
00055 }
00056 }
00057
00058 static std::atomic<uint64_t> delay_rand;
00059
00060
00061 int SpinLockSuggestedDelayNS(int loop) {
00062
00063
00064 uint64_t r = delay_rand.load(std::memory_order_relaxed);
00065 r = 0x5deece66dLL * r + 0xb;
00066 delay_rand.store(r, std::memory_order_relaxed);
00067
00068 if (loop < 0 || loop > 32) {
00069 loop = 32;
00070 }
00071 const int kMinDelay = 128 << 10;
00072
00073 int delay = kMinDelay << (loop / 8);
00074
00075 return delay | ((delay - 1) & static_cast<int>(r));
00076 }
00077
00078 }
00079 }