Change Abseil's SpinLock adaptive_spin_count to a class static variable that can be set by tcmalloc friend classes.

PiperOrigin-RevId: 826226544
Change-Id: I8f8cb5ce199eab9ca63fcd475b536f4a1f512a19
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 4168b8b..41d2b48 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -71,17 +71,23 @@
 }
 
 // Monitor the lock to see if its value changes within some time period
-// (adaptive_spin_count loop iterations). The last value read from the lock
+// (adaptive_spin_count_ loop iterations). The last value read from the lock
 // is returned from the method.
+ABSL_CONST_INIT std::atomic<int> SpinLock::adaptive_spin_count_{0};
 uint32_t SpinLock::SpinLoop() {
   // We are already in the slow path of SpinLock, initialize the
   // adaptive_spin_count here.
-  ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
-  ABSL_CONST_INIT static int adaptive_spin_count = 0;
-  LowLevelCallOnce(&init_adaptive_spin_count,
-                   []() { adaptive_spin_count = NumCPUs() > 1 ? 1000 : 1; });
-
-  int c = adaptive_spin_count;
+  if (adaptive_spin_count_.load(std::memory_order_relaxed) == 0) {
+    int current_spin_count = 0;
+    int new_spin_count = NumCPUs() > 1 ? 1000 : 1;
+    // If this fails, the value will remain unchanged. We may not spin for the
+    // intended duration, but that is still safe. We will try again on the next
+    // call to SpinLoop.
+    adaptive_spin_count_.compare_exchange_weak(
+        current_spin_count, new_spin_count, std::memory_order_relaxed,
+        std::memory_order_relaxed);
+  }
+  int c = adaptive_spin_count_.load(std::memory_order_relaxed);
   uint32_t lock_value;
   do {
     lock_value = lockword_.load(std::memory_order_relaxed);
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index ff2b087..d0e1649 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -47,6 +47,7 @@
 namespace tcmalloc_internal {
 
 class AllocationGuardSpinLockHolder;
+class Static;
 
 }  // namespace tcmalloc_internal
 }  // namespace tcmalloc
@@ -173,6 +174,16 @@
   // Provide access to protected method above.  Use for testing only.
   friend struct SpinLockTest;
   friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder;
+  friend class tcmalloc::tcmalloc_internal::Static;
+
+  static int GetAdaptiveSpinCount() {
+    return adaptive_spin_count_.load(std::memory_order_relaxed);
+  }
+  static void SetAdaptiveSpinCount(int count) {
+    adaptive_spin_count_.store(count, std::memory_order_relaxed);
+  }
+
+  static std::atomic<int> adaptive_spin_count_;
 
  private:
   // lockword_ is used to store the following: