[libc-commits] [libc] [libc] Support configurable errno modes (PR #98287)

Roland McGrath via libc-commits libc-commits at lists.llvm.org
Thu Jul 11 00:08:49 PDT 2024


================
@@ -9,44 +9,91 @@
 #include "libc_errno.h"
 #include "src/__support/CPP/atomic.h"
 
-#ifdef LIBC_TARGET_ARCH_IS_GPU
-// LIBC_THREAD_LOCAL on GPU currently does nothing. So essentially this is just
-// a global errno for gpu to use for now.
+#define LIBC_ERRNO_MODE_UNDEFINED 0x01
+#define LIBC_ERRNO_MODE_THREAD_LOCAL 0x02
+#define LIBC_ERRNO_MODE_GLOBAL 0x04
+#define LIBC_ERRNO_MODE_EXTERNAL 0x08
+#define LIBC_ERRNO_MODE_SYSTEM 0x10
+
+#ifndef LIBC_ERRNO_MODE
+#ifndef LIBC_COPT_PUBLIC_PACKAGING
+// This mode is for unit testing. We just use our internal errno.
+#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_INTERNAL
+#elif defined(LIBC_FULL_BUILD)
+// In full build mode, we provide the errno storage ourselves.
+#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_THREAD_LOCAL
+#else
+#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM
+#endif
+#endif // LIBC_ERRNO_MODE
+
+#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_UNDEFINED &&                            \
+    LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_THREAD_LOCAL &&                         \
+    LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_GLOBAL &&                               \
+    LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_EXTERNAL &&                             \
+    LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM
+#error LIBC_ERRNO_MODE must be one of the following values: \
+LIBC_ERRNO_MODE_NONE, \
+LIBC_ERRNO_MODE_THREAD_LOCAL, \
+LIBC_ERRNO_MODE_GLOBAL, \
+LIBC_ERRNO_MODE_EXTERNAL, \
+LIBC_ERRNO_MODE_SYSTEM
+#endif
+
+namespace LIBC_NAMESPACE {
+
+// Define the global `libc_errno` instance.
+Errno libc_errno;
+
+#if LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_UNDEFINED
+
+void Errno::operator=(int) {}
+Errno::operator int() { return 0; }
+
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_THREAD_LOCAL
+
+namespace {
+LIBC_THREAD_LOCAL int __libc_errno;
+}
+
 extern "C" {
-LIBC_THREAD_LOCAL LIBC_NAMESPACE::cpp::Atomic<int> __llvmlibc_errno;
+int *__llvm_libc_errno(void) { return &__libc_errno; }
 }
 
-void LIBC_NAMESPACE::Errno::operator=(int a) {
-  __llvmlibc_errno.store(a, cpp::MemoryOrder::RELAXED);
+void Errno::operator=(int a) { __libc_errno = a; }
+Errno::operator int() { return __libc_errno; }
+
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_GLOBAL
+
+namespace {
+LIBC_NAMESPACE::cpp::Atomic<int> __libc_errno;
 }
-LIBC_NAMESPACE::Errno::operator int() {
-  return __llvmlibc_errno.load(cpp::MemoryOrder::RELAXED);
+
+extern "C" {
+int *__llvm_libc_errno(void) { return &__libc_errno; }
 }
 
-#elif !defined(LIBC_COPT_PUBLIC_PACKAGING)
-// This mode is for unit testing.  We just use our internal errno.
-LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
+void Errno::operator=(int a) {
+  __libc_errno.store(a, cpp::MemoryOrder::RELAXED);
+}
+Errno::operator int() {
+  return __libc_errno.load(cpp::MemoryOrder::RELAXED);
+}
 
-void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_internal_errno = a; }
-LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_internal_errno; }
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_EXTERNAL
 
-#elif defined(LIBC_FULL_BUILD)
-// This mode is for public libc archive, hermetic, and integration tests.
-// In full build mode, we provide the errno storage ourselves.
 extern "C" {
-LIBC_THREAD_LOCAL int __llvmlibc_errno;
+int *__llvm_libc_errno(void);
----------------
frobtech wrote:

That header has that name because it's implementing `LIBC_NAMESPACE::libc_errno`.  It's true that today it does include `hdr/errno_macros.h`, but that only defines the `E*` constants (necessarily, i.e. in all build modes).

That's a different issue from whether when there is a variable (or variable-like API, such as `errno`) in the public API, we have a `symbol_name.h` header for it in `src/something/` like we do for functions in the public API.

https://github.com/llvm/llvm-project/pull/98287


More information about the libc-commits mailing list