Skip to content

Commit 6925849

Browse files
authored
[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.
1 parent d91ff3f commit 6925849

File tree

9 files changed

+117
-41
lines changed

9 files changed

+117
-41
lines changed

libc/config/baremetal/config.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
{
2+
"errno": {
3+
"LIBC_CONF_ERRNO_MODE": {
4+
"value": "LIBC_ERRNO_MODE_EXTERNAL"
5+
}
6+
},
27
"printf": {
38
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
49
"value": true

libc/config/config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"errno": {
3+
"LIBC_CONF_ERRNO_MODE": {
4+
"value": "",
5+
"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."
6+
}
7+
},
28
"printf": {
39
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
410
"value": false,

libc/config/gpu/config.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
{
2+
"errno": {
3+
"LIBC_CONF_ERRNO_MODE": {
4+
"value": "LIBC_ERRNO_MODE_SHARED"
5+
}
6+
},
27
"printf": {
38
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
49
"value": true

libc/docs/configure.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ to learn about the defaults for your platform and target.
2828
* **"codegen" options**
2929
- ``LIBC_CONF_ENABLE_STRONG_STACK_PROTECTOR``: Enable -fstack-protector-strong to defend against stack smashing attack.
3030
- ``LIBC_CONF_KEEP_FRAME_POINTER``: Keep frame pointer in functions for better debugging experience.
31+
* **"errno" options**
32+
- ``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.
3133
* **"malloc" options**
3234
- ``LIBC_CONF_FREELIST_MALLOC_BUFFER_SIZE``: Default size for the constinit freelist buffer used for the freelist malloc implementation (default 1o 1GB).
3335
* **"math" options**

libc/include/errno.h.def

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,12 @@
2525
#include "llvm-libc-macros/generic-error-number-macros.h"
2626
#endif
2727

28-
#if defined(__AMDGPU__) || defined(__NVPTX__)
29-
extern int __llvmlibc_errno; // Not thread_local!
30-
#else
31-
#ifdef __cplusplus
32-
extern "C" {
33-
extern thread_local int __llvmlibc_errno;
34-
}
35-
#else
36-
extern _Thread_local int __llvmlibc_errno;
37-
#endif // __cplusplus
38-
#endif
28+
__BEGIN_C_DECLS
29+
30+
int *__llvm_libc_errno(void) __NOEXCEPT;
31+
32+
__END_C_DECLS
3933

40-
#define errno __llvmlibc_errno
34+
#define errno (*__llvm_libc_errno())
4135

4236
#endif // LLVM_LIBC_ERRNO_H

libc/src/errno/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@ if(LLVM_LIBC_FULL_BUILD)
99
set(full_build_flag "-DLIBC_FULL_BUILD")
1010
endif()
1111

12+
if(LIBC_CONF_ERRNO_MODE)
13+
set(errno_config_copts "-DLIBC_ERRNO_MODE=${LIBC_CONF_ERRNO_MODE}")
14+
endif()
15+
1216
add_entrypoint_object(
1317
errno
1418
SRCS
1519
libc_errno.cpp
1620
HDRS
21+
errno.h
1722
libc_errno.h # Include this
1823
COMPILE_OPTIONS
1924
${full_build_flag}
25+
${errno_config_copts}
2026
DEPENDS
2127
libc.hdr.errno_macros
2228
libc.src.__support.common

libc/src/errno/errno.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//===-- Implementation header for errno -------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_ERRNO_ERRNO_H
10+
#define LLVM_LIBC_SRC_ERRNO_ERRNO_H
11+
12+
extern "C" int *__llvm_libc_errno();
13+
14+
#endif // LLVM_LIBC_SRC_ERRNO_ERRNO_H

libc/src/errno/libc_errno.cpp

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,90 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "libc_errno.h"
10-
#include "src/__support/CPP/atomic.h"
10+
#include "src/errno/errno.h"
1111
#include "src/__support/macros/config.h"
1212

13-
#ifdef LIBC_TARGET_ARCH_IS_GPU
14-
// LIBC_THREAD_LOCAL on GPU currently does nothing. So essentially this is just
15-
// a global errno for gpu to use for now.
16-
extern "C" {
17-
LIBC_THREAD_LOCAL LIBC_NAMESPACE::cpp::Atomic<int> __llvmlibc_errno;
18-
}
13+
// libc never stores a value; `errno` macro uses get link-time failure.
14+
#define LIBC_ERRNO_MODE_UNDEFINED 1
15+
// libc maintains per-thread state (requires C++ `thread_local` support).
16+
#define LIBC_ERRNO_MODE_THREAD_LOCAL 2
17+
// libc maintains shared state used by all threads, contrary to standard C
18+
// semantics unless always single-threaded; nothing prevents data races.
19+
#define LIBC_ERRNO_MODE_SHARED 3
20+
// libc doesn't maintain any internal state, instead the embedder must define
21+
// `int *__llvm_libc_errno(void);` C function.
22+
#define LIBC_ERRNO_MODE_EXTERNAL 4
23+
// libc uses system `<errno.h>` `errno` macro directly in the overlay mode; in
24+
// fullbuild mode, effectively the same as `LIBC_ERRNO_MODE_EXTERNAL`.
25+
#define LIBC_ERRNO_MODE_SYSTEM 5
26+
27+
#ifndef LIBC_ERRNO_MODE
28+
#if defined(LIBC_FULL_BUILD) || !defined(LIBC_COPT_PUBLIC_PACKAGING)
29+
#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_THREAD_LOCAL
30+
#else
31+
#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM
32+
#endif
33+
#endif // LIBC_ERRNO_MODE
34+
35+
#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_UNDEFINED && \
36+
LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_THREAD_LOCAL && \
37+
LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SHARED && \
38+
LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_EXTERNAL && \
39+
LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM
40+
#error LIBC_ERRNO_MODE must be one of the following values: \
41+
LIBC_ERRNO_MODE_UNDEFINED, \
42+
LIBC_ERRNO_MODE_THREAD_LOCAL, \
43+
LIBC_ERRNO_MODE_SHARED, \
44+
LIBC_ERRNO_MODE_EXTERNAL, \
45+
LIBC_ERRNO_MODE_SYSTEM
46+
#endif
47+
48+
namespace LIBC_NAMESPACE_DECL {
49+
50+
// Define the global `libc_errno` instance.
51+
Errno libc_errno;
52+
53+
#if LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_UNDEFINED
54+
55+
void Errno::operator=(int) {}
56+
Errno::operator int() { return 0; }
1957

20-
void LIBC_NAMESPACE::Errno::operator=(int a) {
21-
__llvmlibc_errno.store(a, cpp::MemoryOrder::RELAXED);
58+
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_THREAD_LOCAL
59+
60+
namespace {
61+
LIBC_THREAD_LOCAL int thread_errno;
2262
}
23-
LIBC_NAMESPACE::Errno::operator int() {
24-
return __llvmlibc_errno.load(cpp::MemoryOrder::RELAXED);
63+
64+
extern "C" {
65+
int *__llvm_libc_errno() { return &thread_errno; }
2566
}
2667

27-
#elif !defined(LIBC_COPT_PUBLIC_PACKAGING)
28-
// This mode is for unit testing. We just use our internal errno.
29-
LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
68+
void Errno::operator=(int a) { thread_errno = a; }
69+
Errno::operator int() { return thread_errno; }
3070

31-
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_internal_errno = a; }
32-
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_internal_errno; }
71+
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SHARED
72+
73+
namespace {
74+
int shared_errno;
75+
}
3376

34-
#elif defined(LIBC_FULL_BUILD)
35-
// This mode is for public libc archive, hermetic, and integration tests.
36-
// In full build mode, we provide the errno storage ourselves.
3777
extern "C" {
38-
LIBC_THREAD_LOCAL int __llvmlibc_errno;
78+
int *__llvm_libc_errno() { return &shared_errno; }
3979
}
4080

41-
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
42-
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_errno; }
81+
void Errno::operator=(int a) { shared_errno = a; }
82+
Errno::operator int() { return shared_errno; }
4383

44-
#else
45-
void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
46-
LIBC_NAMESPACE::Errno::operator int() { return errno; }
84+
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_EXTERNAL
4785

48-
#endif // LIBC_FULL_BUILD
86+
void Errno::operator=(int a) { *__llvm_libc_errno() = a; }
87+
Errno::operator int() { return *__llvm_libc_errno(); }
88+
89+
#elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SYSTEM
90+
91+
void Errno::operator=(int a) { errno = a; }
92+
Errno::operator int() { return errno; }
93+
94+
#endif
4995

50-
namespace LIBC_NAMESPACE_DECL {
51-
// Define the global `libc_errno` instance.
52-
Errno libc_errno;
5396
} // namespace LIBC_NAMESPACE_DECL

libc/src/errno/libc_errno.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
// - Still depend on libc.src.errno.errno
3333

3434
namespace LIBC_NAMESPACE_DECL {
35+
3536
struct Errno {
3637
void operator=(int);
3738
operator int();

0 commit comments

Comments
 (0)