spinlock_wait.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 // The OS-specific header included below must provide two calls:
00016 // AbslInternalSpinLockDelay() and AbslInternalSpinLockWake().
00017 // See spinlock_wait.h for the specs.
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 // See spinlock_wait.h for spec.
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);  // no matching transition
00049     } else if (trans[i].to == v ||                   // null transition
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 // Return a suggested delay in nanoseconds for iteration number "loop"
00061 int SpinLockSuggestedDelayNS(int loop) {
00062   // Weak pseudo-random number generator to get some spread between threads
00063   // when many are spinning.
00064   uint64_t r = delay_rand.load(std::memory_order_relaxed);
00065   r = 0x5deece66dLL * r + 0xb;   // numbers from nrand48()
00066   delay_rand.store(r, std::memory_order_relaxed);
00067 
00068   if (loop < 0 || loop > 32) {   // limit loop to 0..32
00069     loop = 32;
00070   }
00071   const int kMinDelay = 128 << 10;  // 128us
00072   // Double delay every 8 iterations, up to 16x (2ms).
00073   int delay = kMinDelay << (loop / 8);
00074   // Randomize in delay..2*delay range, for resulting 128us..4ms range.
00075   return delay | ((delay - 1) & static_cast<int>(r));
00076 }
00077 
00078 }  // namespace base_internal
00079 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15