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

via libc-commits libc-commits at lists.llvm.org
Sat Jul 13 10:52:46 PDT 2024


Author: Petr Hosek
Date: 2024-07-13T10:52:42-07:00
New Revision: 69258491d201bf6d96a8a9bac2ea80a1b14d9cd4

URL: https://github.com/llvm/llvm-project/commit/69258491d201bf6d96a8a9bac2ea80a1b14d9cd4
DIFF: https://github.com/llvm/llvm-project/commit/69258491d201bf6d96a8a9bac2ea80a1b14d9cd4.diff

LOG: [libc] Support configurable errno modes (#98287)

Rather than selecting the errno implementation based on the platform
which doesn't provide the necessary flexibility, make it configurable.

The errno value location is returned by `int *__llvm_libc_errno()` which
is a common design used by other C libraries.

Added: 
    libc/src/errno/errno.h

Modified: 
    libc/config/baremetal/config.json
    libc/config/config.json
    libc/config/gpu/config.json
    libc/docs/configure.rst
    libc/include/errno.h.def
    libc/src/errno/CMakeLists.txt
    libc/src/errno/libc_errno.cpp
    libc/src/errno/libc_errno.h

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/config.json b/libc/config/baremetal/config.json
index dda4c42425755..b7426dd341d97 100644
--- a/libc/config/baremetal/config.json
+++ b/libc/config/baremetal/config.json
@@ -1,4 +1,9 @@
 {
+  "errno": {
+    "LIBC_CONF_ERRNO_MODE": {
+      "value": "LIBC_ERRNO_MODE_EXTERNAL"
+    }
+  },
   "printf": {
     "LIBC_CONF_PRINTF_DISABLE_FLOAT": {
       "value": true

diff  --git a/libc/config/config.json b/libc/config/config.json
index e8feab20175f4..3a9c08d195445 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -1,4 +1,10 @@
 {
+  "errno": {
+    "LIBC_CONF_ERRNO_MODE": {
+      "value": "",
+      "doc": "The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM."
+    }
+  },
   "printf": {
     "LIBC_CONF_PRINTF_DISABLE_FLOAT": {
       "value": false,

diff  --git a/libc/config/gpu/config.json b/libc/config/gpu/config.json
index 71107d26ea7ab..954163947b8a4 100644
--- a/libc/config/gpu/config.json
+++ b/libc/config/gpu/config.json
@@ -1,4 +1,9 @@
 {
+  "errno": {
+    "LIBC_CONF_ERRNO_MODE": {
+      "value": "LIBC_ERRNO_MODE_SHARED"
+    }
+  },
   "printf": {
     "LIBC_CONF_PRINTF_DISABLE_FLOAT": {
       "value": true

diff  --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 9c641ef94570f..24ef2ef189ffd 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -28,6 +28,8 @@ to learn about the defaults for your platform and target.
 * **"codegen" options**
     - ``LIBC_CONF_ENABLE_STRONG_STACK_PROTECTOR``: Enable -fstack-protector-strong to defend against stack smashing attack.
     - ``LIBC_CONF_KEEP_FRAME_POINTER``: Keep frame pointer in functions for better debugging experience.
+* **"errno" options**
+    - ``LIBC_CONF_ERRNO_MODE``: The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM.
 * **"malloc" options**
     - ``LIBC_CONF_FREELIST_MALLOC_BUFFER_SIZE``: Default size for the constinit freelist buffer used for the freelist malloc implementation (default 1o 1GB).
 * **"math" options**

diff  --git a/libc/include/errno.h.def b/libc/include/errno.h.def
index 1f7120e63bfc9..aa1f6c9e48444 100644
--- a/libc/include/errno.h.def
+++ b/libc/include/errno.h.def
@@ -25,18 +25,12 @@
 #include "llvm-libc-macros/generic-error-number-macros.h"
 #endif
 
-#if defined(__AMDGPU__) || defined(__NVPTX__)
-extern int __llvmlibc_errno; // Not thread_local!
-#else
-#ifdef __cplusplus
-extern "C" {
-extern thread_local int __llvmlibc_errno;
-}
-#else
-extern _Thread_local int __llvmlibc_errno;
-#endif // __cplusplus
-#endif
+__BEGIN_C_DECLS
+
+int *__llvm_libc_errno(void) __NOEXCEPT;
+
+__END_C_DECLS
 
-#define errno __llvmlibc_errno
+#define errno (*__llvm_libc_errno())
 
 #endif // LLVM_LIBC_ERRNO_H

diff  --git a/libc/src/errno/CMakeLists.txt b/libc/src/errno/CMakeLists.txt
index 2622e51261cc3..b05fd4e31ff68 100644
--- a/libc/src/errno/CMakeLists.txt
+++ b/libc/src/errno/CMakeLists.txt
@@ -9,14 +9,20 @@ if(LLVM_LIBC_FULL_BUILD)
   set(full_build_flag "-DLIBC_FULL_BUILD")
 endif()
 
+if(LIBC_CONF_ERRNO_MODE)
+  set(errno_config_copts "-DLIBC_ERRNO_MODE=${LIBC_CONF_ERRNO_MODE}")
+endif()
+
 add_entrypoint_object(
   errno
   SRCS
     libc_errno.cpp
   HDRS
+    errno.h
     libc_errno.h     # Include this
   COMPILE_OPTIONS
     ${full_build_flag}
+    ${errno_config_copts}
   DEPENDS
     libc.hdr.errno_macros
     libc.src.__support.common

diff  --git a/libc/src/errno/errno.h b/libc/src/errno/errno.h
new file mode 100644
index 0000000000000..a2df93513ec62
--- /dev/null
+++ b/libc/src/errno/errno.h
@@ -0,0 +1,14 @@
+//===-- Implementation header for errno -------------------------*- 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 LLVM_LIBC_SRC_ERRNO_ERRNO_H
+#define LLVM_LIBC_SRC_ERRNO_ERRNO_H
+
+extern "C" int *__llvm_libc_errno();
+
+#endif // LLVM_LIBC_SRC_ERRNO_ERRNO_H

diff  --git a/libc/src/errno/libc_errno.cpp b/libc/src/errno/libc_errno.cpp
index 341636f0495c1..f7bd3a3b9eb4b 100644
--- a/libc/src/errno/libc_errno.cpp
+++ b/libc/src/errno/libc_errno.cpp
@@ -7,47 +7,90 @@
 //===----------------------------------------------------------------------===//
 
 #include "libc_errno.h"
-#include "src/__support/CPP/atomic.h"
+#include "src/errno/errno.h"
 #include "src/__support/macros/config.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.
-extern "C" {
-LIBC_THREAD_LOCAL LIBC_NAMESPACE::cpp::Atomic<int> __llvmlibc_errno;
-}
+// libc never stores a value; `errno` macro uses get link-time failure.
+#define LIBC_ERRNO_MODE_UNDEFINED 1
+// libc maintains per-thread state (requires C++ `thread_local` support).
+#define LIBC_ERRNO_MODE_THREAD_LOCAL 2
+// libc maintains shared state used by all threads, contrary to standard C
+// semantics unless always single-threaded; nothing prevents data races.
+#define LIBC_ERRNO_MODE_SHARED 3
+// libc doesn't maintain any internal state, instead the embedder must define
+// `int *__llvm_libc_errno(void);` C function.
+#define LIBC_ERRNO_MODE_EXTERNAL 4
+// libc uses system `<errno.h>` `errno` macro directly in the overlay mode; in
+// fullbuild mode, effectively the same as `LIBC_ERRNO_MODE_EXTERNAL`.
+#define LIBC_ERRNO_MODE_SYSTEM 5
+
+#ifndef LIBC_ERRNO_MODE
+#if defined(LIBC_FULL_BUILD) || !defined(LIBC_COPT_PUBLIC_PACKAGING)
+#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_SHARED &&                               \
+    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_UNDEFINED, \
+LIBC_ERRNO_MODE_THREAD_LOCAL, \
+LIBC_ERRNO_MODE_SHARED, \
+LIBC_ERRNO_MODE_EXTERNAL, \
+LIBC_ERRNO_MODE_SYSTEM
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+// 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; }
 
-void LIBC_NAMESPACE::Errno::operator=(int a) {
-  __llvmlibc_errno.store(a, cpp::MemoryOrder::RELAXED);
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_THREAD_LOCAL
+
+namespace {
+LIBC_THREAD_LOCAL int thread_errno;
 }
-LIBC_NAMESPACE::Errno::operator int() {
-  return __llvmlibc_errno.load(cpp::MemoryOrder::RELAXED);
+
+extern "C" {
+int *__llvm_libc_errno() { return &thread_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) { thread_errno = a; }
+Errno::operator int() { return thread_errno; }
 
-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_SHARED
+
+namespace {
+int shared_errno;
+}
 
-#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() { return &shared_errno; }
 }
 
-void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
-LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_errno; }
+void Errno::operator=(int a) { shared_errno = a; }
+Errno::operator int() { return shared_errno; }
 
-#else
-void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
-LIBC_NAMESPACE::Errno::operator int() { return errno; }
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_EXTERNAL
 
-#endif // LIBC_FULL_BUILD
+void Errno::operator=(int a) { *__llvm_libc_errno() = a; }
+Errno::operator int() { return *__llvm_libc_errno(); }
+
+#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SYSTEM
+
+void Errno::operator=(int a) { errno = a; }
+Errno::operator int() { return errno; }
+
+#endif
 
-namespace LIBC_NAMESPACE_DECL {
-// Define the global `libc_errno` instance.
-Errno libc_errno;
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/errno/libc_errno.h b/libc/src/errno/libc_errno.h
index 8d28a01c8b7bb..c6c6b20b48251 100644
--- a/libc/src/errno/libc_errno.h
+++ b/libc/src/errno/libc_errno.h
@@ -32,6 +32,7 @@
 // - Still depend on libc.src.errno.errno
 
 namespace LIBC_NAMESPACE_DECL {
+
 struct Errno {
   void operator=(int);
   operator int();


        


More information about the libc-commits mailing list