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 #ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ 00016 #define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ 00017 00018 // Operations to make atomic transitions on a word, and to allow 00019 // waiting for those transitions to become possible. 00020 00021 #include <stdint.h> 00022 #include <atomic> 00023 00024 #include "absl/base/internal/scheduling_mode.h" 00025 00026 namespace absl { 00027 namespace base_internal { 00028 00029 // SpinLockWait() waits until it can perform one of several transitions from 00030 // "from" to "to". It returns when it performs a transition where done==true. 00031 struct SpinLockWaitTransition { 00032 uint32_t from; 00033 uint32_t to; 00034 bool done; 00035 }; 00036 00037 // Wait until *w can transition from trans[i].from to trans[i].to for some i 00038 // satisfying 0<=i<n && trans[i].done, atomically make the transition, 00039 // then return the old value of *w. Make any other atomic transitions 00040 // where !trans[i].done, but continue waiting. 00041 uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, 00042 const SpinLockWaitTransition trans[], 00043 SchedulingMode scheduling_mode); 00044 00045 // If possible, wake some thread that has called SpinLockDelay(w, ...). If 00046 // "all" is true, wake all such threads. This call is a hint, and on some 00047 // systems it may be a no-op; threads calling SpinLockDelay() will always wake 00048 // eventually even if SpinLockWake() is never called. 00049 void SpinLockWake(std::atomic<uint32_t> *w, bool all); 00050 00051 // Wait for an appropriate spin delay on iteration "loop" of a 00052 // spin loop on location *w, whose previously observed value was "value". 00053 // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, 00054 // or may wait for a delay that can be truncated by a call to SpinLockWake(w). 00055 // In all cases, it must return in bounded time even if SpinLockWake() is not 00056 // called. 00057 void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, 00058 base_internal::SchedulingMode scheduling_mode); 00059 00060 // Helper used by AbslInternalSpinLockDelay. 00061 // Returns a suggested delay in nanoseconds for iteration number "loop". 00062 int SpinLockSuggestedDelayNS(int loop); 00063 00064 } // namespace base_internal 00065 } // namespace absl 00066 00067 // In some build configurations we pass --detect-odr-violations to the 00068 // gold linker. This causes it to flag weak symbol overrides as ODR 00069 // violations. Because ODR only applies to C++ and not C, 00070 // --detect-odr-violations ignores symbols not mangled with C++ names. 00071 // By changing our extension points to be extern "C", we dodge this 00072 // check. 00073 extern "C" { 00074 void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all); 00075 void AbslInternalSpinLockDelay( 00076 std::atomic<uint32_t> *w, uint32_t value, int loop, 00077 absl::base_internal::SchedulingMode scheduling_mode); 00078 } 00079 00080 inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w, 00081 bool all) { 00082 AbslInternalSpinLockWake(w, all); 00083 } 00084 00085 inline void absl::base_internal::SpinLockDelay( 00086 std::atomic<uint32_t> *w, uint32_t value, int loop, 00087 absl::base_internal::SchedulingMode scheduling_mode) { 00088 AbslInternalSpinLockDelay(w, value, loop, scheduling_mode); 00089 } 00090 00091 #endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_