diff options
| author | Petr Hosek <phosek@google.com> | 2024-07-13 10:52:42 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-13 10:52:42 -0700 |
| commit | 69258491d201bf6d96a8a9bac2ea80a1b14d9cd4 (patch) | |
| tree | 1c9ef8e2df479dd14c2d4f0d819d6350621c1d8b /libc/src/errno/libc_errno.cpp | |
| parent | d91ff3f2409a721b61b68c6a8438ea6c59323df8 (diff) | |
[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.
Diffstat (limited to 'libc/src/errno/libc_errno.cpp')
| -rw-r--r-- | libc/src/errno/libc_errno.cpp | 101 |
1 files changed, 72 insertions, 29 deletions
diff --git a/libc/src/errno/libc_errno.cpp b/libc/src/errno/libc_errno.cpp index 341636f0495c..f7bd3a3b9eb4 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 |
