[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.
This commit is contained in:
parent
d91ff3f240
commit
69258491d2
@ -1,4 +1,9 @@
|
||||
{
|
||||
"errno": {
|
||||
"LIBC_CONF_ERRNO_MODE": {
|
||||
"value": "LIBC_ERRNO_MODE_EXTERNAL"
|
||||
}
|
||||
},
|
||||
"printf": {
|
||||
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
|
||||
"value": true
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
{
|
||||
"errno": {
|
||||
"LIBC_CONF_ERRNO_MODE": {
|
||||
"value": "LIBC_ERRNO_MODE_SHARED"
|
||||
}
|
||||
},
|
||||
"printf": {
|
||||
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
|
||||
"value": true
|
||||
|
||||
@ -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**
|
||||
|
||||
@ -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
|
||||
|
||||
#define errno __llvmlibc_errno
|
||||
int *__llvm_libc_errno(void) __NOEXCEPT;
|
||||
|
||||
__END_C_DECLS
|
||||
|
||||
#define errno (*__llvm_libc_errno())
|
||||
|
||||
#endif // LLVM_LIBC_ERRNO_H
|
||||
|
||||
@ -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
|
||||
|
||||
14
libc/src/errno/errno.h
Normal file
14
libc/src/errno/errno.h
Normal file
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
void LIBC_NAMESPACE::Errno::operator=(int a) {
|
||||
__llvmlibc_errno.store(a, cpp::MemoryOrder::RELAXED);
|
||||
}
|
||||
LIBC_NAMESPACE::Errno::operator int() {
|
||||
return __llvmlibc_errno.load(cpp::MemoryOrder::RELAXED);
|
||||
}
|
||||
|
||||
#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 LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_internal_errno = a; }
|
||||
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_internal_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;
|
||||
}
|
||||
|
||||
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
|
||||
LIBC_NAMESPACE::Errno::operator int() { return __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
|
||||
void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
|
||||
LIBC_NAMESPACE::Errno::operator int() { return errno; }
|
||||
#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM
|
||||
#endif
|
||||
#endif // LIBC_ERRNO_MODE
|
||||
|
||||
#endif // LIBC_FULL_BUILD
|
||||
#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; }
|
||||
|
||||
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_THREAD_LOCAL
|
||||
|
||||
namespace {
|
||||
LIBC_THREAD_LOCAL int thread_errno;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int *__llvm_libc_errno() { return &thread_errno; }
|
||||
}
|
||||
|
||||
void Errno::operator=(int a) { thread_errno = a; }
|
||||
Errno::operator int() { return thread_errno; }
|
||||
|
||||
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SHARED
|
||||
|
||||
namespace {
|
||||
int shared_errno;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int *__llvm_libc_errno() { return &shared_errno; }
|
||||
}
|
||||
|
||||
void Errno::operator=(int a) { shared_errno = a; }
|
||||
Errno::operator int() { return shared_errno; }
|
||||
|
||||
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_EXTERNAL
|
||||
|
||||
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
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
// - Still depend on libc.src.errno.errno
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
struct Errno {
|
||||
void operator=(int);
|
||||
operator int();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user