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 | |
parent | d91ff3f2409a721b61b68c6a8438ea6c59323df8 (diff) | |
download | llvm-69258491d201bf6d96a8a9bac2ea80a1b14d9cd4.zip llvm-69258491d201bf6d96a8a9bac2ea80a1b14d9cd4.tar.gz llvm-69258491d201bf6d96a8a9bac2ea80a1b14d9cd4.tar.bz2 |
[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')
-rw-r--r-- | libc/src/errno/CMakeLists.txt | 6 | ||||
-rw-r--r-- | libc/src/errno/errno.h | 14 | ||||
-rw-r--r-- | libc/src/errno/libc_errno.cpp | 101 | ||||
-rw-r--r-- | libc/src/errno/libc_errno.h | 1 |
4 files changed, 93 insertions, 29 deletions
diff --git a/libc/src/errno/CMakeLists.txt b/libc/src/errno/CMakeLists.txt index 2622e51..b05fd4e 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 0000000..a2df935 --- /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 341636f0..f7bd3a3 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 8d28a01..c6c6b20 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(); |