spinlock_wait.h (3850B)
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 15 #ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ 16 #define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ 17 18 // Operations to make atomic transitions on a word, and to allow 19 // waiting for those transitions to become possible. 20 21 #include <stdint.h> 22 #include <atomic> 23 24 #include "absl/base/internal/scheduling_mode.h" 25 26 namespace absl { 27 ABSL_NAMESPACE_BEGIN 28 namespace base_internal { 29 30 // SpinLockWait() waits until it can perform one of several transitions from 31 // "from" to "to". It returns when it performs a transition where done==true. 32 struct SpinLockWaitTransition { 33 uint32_t from; 34 uint32_t to; 35 bool done; 36 }; 37 38 // Wait until *w can transition from trans[i].from to trans[i].to for some i 39 // satisfying 0<=i<n && trans[i].done, atomically make the transition, 40 // then return the old value of *w. Make any other atomic transitions 41 // where !trans[i].done, but continue waiting. 42 // 43 // Wakeups for threads blocked on SpinLockWait do not respect priorities. 44 uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, 45 const SpinLockWaitTransition trans[], 46 SchedulingMode scheduling_mode); 47 48 // If possible, wake some thread that has called SpinLockDelay(w, ...). If `all` 49 // is true, wake all such threads. On some systems, this may be a no-op; on 50 // those systems, threads calling SpinLockDelay() will always wake eventually 51 // even if SpinLockWake() is never called. 52 void SpinLockWake(std::atomic<uint32_t> *w, bool all); 53 54 // Wait for an appropriate spin delay on iteration "loop" of a 55 // spin loop on location *w, whose previously observed value was "value". 56 // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, 57 // or may wait for a call to SpinLockWake(w). 58 void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, 59 base_internal::SchedulingMode scheduling_mode); 60 61 // Helper used by AbslInternalSpinLockDelay. 62 // Returns a suggested delay in nanoseconds for iteration number "loop". 63 int SpinLockSuggestedDelayNS(int loop); 64 65 } // namespace base_internal 66 ABSL_NAMESPACE_END 67 } // namespace absl 68 69 // In some build configurations we pass --detect-odr-violations to the 70 // gold linker. This causes it to flag weak symbol overrides as ODR 71 // violations. Because ODR only applies to C++ and not C, 72 // --detect-odr-violations ignores symbols not mangled with C++ names. 73 // By changing our extension points to be extern "C", we dodge this 74 // check. 75 extern "C" { 76 void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w, 77 bool all); 78 void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( 79 std::atomic<uint32_t> *w, uint32_t value, int loop, 80 absl::base_internal::SchedulingMode scheduling_mode); 81 } 82 83 inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w, 84 bool all) { 85 ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all); 86 } 87 88 inline void absl::base_internal::SpinLockDelay( 89 std::atomic<uint32_t> *w, uint32_t value, int loop, 90 absl::base_internal::SchedulingMode scheduling_mode) { 91 ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay) 92 (w, value, loop, scheduling_mode); 93 } 94 95 #endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_