spinlock_wait.h 3.8 KB

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