[libc++] Enable <atomic> when threads are disabled

std::atomic is, for the most part, just a thin veneer on top of compiler
builtins. Hence, it should be available even when threads are not available
on the system, and in fact there has been requests for such support.

This patch:
- Moves __libcpp_thread_poll_with_backoff to its own header so it can
  be used in <atomic> when threads are disabled.
- Adds a dummy backoff policy for atomic polling that doesn't know about
  threads.
- Adjusts the <atomic> feature-test macros so they are provided even when
  threads are disabled.
- Runs the <atomic> tests when threads are disabled.

rdar://77873569

Differential Revision: https://reviews.llvm.org/D114109

NOKEYCHECK=True
GitOrigin-RevId: 92832e4889ae6038cc8b3e6e449af2a9b9374ab4
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 9d7abc8..1947aa1 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -283,6 +283,7 @@
   __support/xlocale/__nop_locale_mgmt.h
   __support/xlocale/__posix_l_fallback.h
   __support/xlocale/__strtonum_fallback.h
+  __thread/poll_with_backoff.h
   __threading_support
   __tree
   __tuple
diff --git a/include/__config b/include/__config
index 18d0c86..dbf4383 100644
--- a/include/__config
+++ b/include/__config
@@ -1190,10 +1190,9 @@
 #  define _LIBCPP_HAS_GCC_ATOMIC_IMP
 #endif
 
-#if (!defined(_LIBCPP_HAS_C_ATOMIC_IMP) && \
-     !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) && \
-     !defined(_LIBCPP_HAS_EXTERNAL_ATOMIC_IMP)) \
-     || defined(_LIBCPP_HAS_NO_THREADS)
+#if !defined(_LIBCPP_HAS_C_ATOMIC_IMP) && \
+    !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) && \
+    !defined(_LIBCPP_HAS_EXTERNAL_ATOMIC_IMP)
 #  define _LIBCPP_HAS_NO_ATOMIC_HEADER
 #else
 #  ifndef _LIBCPP_ATOMIC_FLAG_TYPE
diff --git a/include/__memory/shared_ptr.h b/include/__memory/shared_ptr.h
index 7b08641..9c7df88 100644
--- a/include/__memory/shared_ptr.h
+++ b/include/__memory/shared_ptr.h
@@ -1572,7 +1572,7 @@
 operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p);
 
 
-#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
+#if !defined(_LIBCPP_HAS_NO_THREADS)
 
 class _LIBCPP_TYPE_VIS __sp_mut
 {
@@ -1712,7 +1712,7 @@
     return atomic_compare_exchange_weak(__p, __v, __w);
 }
 
-#endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
+#endif // !defined(_LIBCPP_HAS_NO_THREADS)
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/include/__thread/poll_with_backoff.h b/include/__thread/poll_with_backoff.h
new file mode 100644
index 0000000..e1d8a9c
--- /dev/null
+++ b/include/__thread/poll_with_backoff.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___THREAD_POLL_WITH_BACKOFF_H
+#define _LIBCPP___THREAD_POLL_WITH_BACKOFF_H
+
+#include <__config>
+#include <chrono>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64;
+
+// Polls a thread for a condition given by a predicate, and backs off based on a backoff policy
+// before polling again.
+//
+// - __f is the "test function" that should return true if polling succeeded, and false if it failed.
+//
+// - __bf is the "backoff policy", which is called with the duration since we started polling. It should
+//   return false in order to resume polling, and true if polling should stop entirely for some reason.
+//   In general, backoff policies sleep for some time before returning control to the polling loop.
+//
+// - __max_elapsed is the maximum duration to try polling for. If the maximum duration is exceeded,
+//   the polling loop will return false to report a timeout.
+template<class _Fn, class _BFn>
+_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI
+bool __libcpp_thread_poll_with_backoff(_Fn&& __f, _BFn&& __bf, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) {
+    auto const __start = chrono::high_resolution_clock::now();
+    for (int __count = 0;;) {
+      if (__f())
+        return true; // _Fn completion means success
+      if (__count < __libcpp_polling_count) {
+        __count += 1;
+        continue;
+      }
+      chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start;
+      if (__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed)
+          return false; // timeout failure
+      if (__bf(__elapsed))
+        return false; // _BFn completion means failure
+    }
+}
+
+// A trivial backoff policy that always immediately returns the control to
+// the polling loop.
+//
+// This is not very well-behaved since it will cause the polling loop to spin,
+// so this should most likely only be used on single-threaded systems where there
+// are no other threads to compete with.
+struct __spinning_backoff_policy {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
+  bool operator()(chrono::nanoseconds const&) const {
+      return false;
+  }
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___THREAD_POLL_WITH_BACKOFF_H
diff --git a/include/__threading_support b/include/__threading_support
index 2242a69..0094fca 100644
--- a/include/__threading_support
+++ b/include/__threading_support
@@ -12,6 +12,7 @@
 
 #include <__availability>
 #include <__config>
+#include <__thread/poll_with_backoff.h>
 #include <chrono>
 #include <errno.h>
 #include <iosfwd>
@@ -267,29 +268,6 @@
   }
 };
 
-static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64;
-
-template<class _Fn, class _BFn>
-_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
-bool __libcpp_thread_poll_with_backoff(
-  _Fn && __f, _BFn && __bf, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero())
-{
-    auto const __start = chrono::high_resolution_clock::now();
-    for(int __count = 0;;) {
-      if(__f())
-        return true; // _Fn completion means success
-      if(__count < __libcpp_polling_count) {
-        __count += 1;
-        continue;
-      }
-      chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start;
-      if(__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed)
-          return false; // timeout failure
-      if(__bf(__elapsed))
-        return false; // _BFn completion means failure
-    }
-}
-
 #if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
      defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL))
 
diff --git a/include/atomic b/include/atomic
index 252ab21..cfd0e1d 100644
--- a/include/atomic
+++ b/include/atomic
@@ -520,20 +520,21 @@
 
 #include <__availability>
 #include <__config>
-#include <__threading_support>
+#include <__thread/poll_with_backoff.h>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
 #include <type_traits>
 #include <version>
 
+#ifndef _LIBCPP_HAS_NO_THREADS
+# include <__threading_support>
+#endif
+
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
-#ifdef _LIBCPP_HAS_NO_THREADS
-# error <atomic> is not supported on this single threaded system
-#endif
 #ifdef _LIBCPP_HAS_NO_ATOMIC_HEADER
 # error <atomic> is not implemented
 #endif
@@ -1455,6 +1456,16 @@
 
 using __cxx_atomic_contention_t = __cxx_atomic_impl<__cxx_contention_t>;
 
+#if defined(_LIBCPP_HAS_NO_THREADS)
+#   define _LIBCPP_HAS_NO_PLATFORM_WAIT
+#endif
+
+// TODO:
+// _LIBCPP_HAS_NO_PLATFORM_WAIT is currently a "dead" macro, in the sense that
+// it is not tied anywhere into the build system or even documented. We should
+// clean it up because it is technically never defined except when threads are
+// disabled. We should clean it up in its own changeset in case we break "bad"
+// users.
 #ifndef _LIBCPP_HAS_NO_PLATFORM_WAIT
 
 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*);
@@ -1506,7 +1517,12 @@
 template <class _Atp, class _Fn>
 _LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp*, _Fn && __test_fn)
 {
-    return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy());
+#if defined(_LIBCPP_HAS_NO_THREADS)
+    using _Policy = __spinning_backoff_policy;
+#else
+    using _Policy = __libcpp_timed_backoff_policy;
+#endif
+    return __libcpp_thread_poll_with_backoff(__test_fn, _Policy());
 }
 
 #endif // _LIBCPP_HAS_NO_PLATFORM_WAIT
diff --git a/include/module.modulemap b/include/module.modulemap
index b159d58..f34442e 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -799,6 +799,10 @@
   module thread {
     header "thread"
     export *
+
+    module __thread {
+      module poll_with_backoff { private header "__thread/poll_with_backoff.h" }
+    }
   }
   module tuple {
     header "tuple"
diff --git a/include/thread b/include/thread
index f136da5..a51a11c 100644
--- a/include/thread
+++ b/include/thread
@@ -86,6 +86,7 @@
 #include <__debug>
 #include <__functional_base>
 #include <__mutex_base>
+#include <__thread/poll_with_backoff.h>
 #include <__threading_support>
 #include <__utility/decay_copy.h>
 #include <__utility/forward.h>
diff --git a/include/version b/include/version
index a4809eb..d2286f5 100644
--- a/include/version
+++ b/include/version
@@ -205,9 +205,7 @@
 # define __cpp_lib_apply                                201603L
 # define __cpp_lib_array_constexpr                      201603L
 # define __cpp_lib_as_const                             201510L
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-#   define __cpp_lib_atomic_is_always_lock_free         201603L
-# endif
+# define __cpp_lib_atomic_is_always_lock_free           201603L
 # define __cpp_lib_bool_constant                        201505L
 // # define __cpp_lib_boyer_moore_searcher                 201603L
 # define __cpp_lib_byte                                 201603L
@@ -261,25 +259,13 @@
 # undef  __cpp_lib_array_constexpr
 # define __cpp_lib_array_constexpr                      201811L
 // # define __cpp_lib_assume_aligned                       201811L
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-#   define __cpp_lib_atomic_flag_test                   201907L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-// #   define __cpp_lib_atomic_float                       201711L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-#   define __cpp_lib_atomic_lock_free_type_aliases      201907L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-// #   define __cpp_lib_atomic_ref                         201806L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-// #   define __cpp_lib_atomic_shared_ptr                  201711L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS)
-#   define __cpp_lib_atomic_value_initialization        201911L
-# endif
-# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)
+# define __cpp_lib_atomic_flag_test                     201907L
+// # define __cpp_lib_atomic_float                         201711L
+# define __cpp_lib_atomic_lock_free_type_aliases        201907L
+// # define __cpp_lib_atomic_ref                           201806L
+// # define __cpp_lib_atomic_shared_ptr                    201711L
+# define __cpp_lib_atomic_value_initialization          201911L
+# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)
 #   define __cpp_lib_atomic_wait                        201907L
 # endif
 # if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)