Skip to content

Commit 28699e3

Browse files
authored
[libc] Update libc_errno to work correctly in both overlay and full build modes. (llvm#80177)
1 parent e0e6236 commit 28699e3

File tree

14 files changed

+101
-86
lines changed

14 files changed

+101
-86
lines changed

libc/include/errno.h.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@
4444
#endif
4545

4646
#if !defined(__AMDGPU__) && !defined(__NVPTX__)
47+
48+
#ifdef __cplusplus
49+
extern "C" {
50+
extern thread_local int __llvmlibc_errno;
51+
}
52+
#else
4753
extern _Thread_local int __llvmlibc_errno;
54+
#endif // __cplusplus
55+
4856
#define errno __llvmlibc_errno
4957
#endif
5058

libc/src/errno/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1+
# If we are in full build mode, we will provide the errno definition ourselves,
2+
# and if we are in overlay mode, we will just re-use the system's errno.
3+
# We are passing LIBC_FULL_BUILD flag in full build mode so that the
4+
# implementation of libc_errno will know if we are in full build mode or not.
5+
6+
# TODO: Move LIBC_FULL_BUILD flag to _get_common_compile_options.
7+
set(full_build_flag "")
8+
if(LLVM_LIBC_FULL_BUILD)
9+
set(full_build_flag "-DLIBC_FULL_BUILD")
10+
endif()
11+
112
add_entrypoint_object(
213
errno
314
SRCS
415
libc_errno.cpp
516
HDRS
617
libc_errno.h # Include this
18+
COMPILE_OPTIONS
19+
${full_build_flag}
720
DEPENDS
821
libc.include.errno
922
libc.src.__support.common

libc/src/errno/libc_errno.cpp

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,48 @@
1-
//===-- Implementation of errno -------------------------------------------===//
1+
//===-- Implementation of libc_errno --------------------------------------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "src/__support/macros/attributes.h"
10-
#include "src/__support/macros/properties/architectures.h"
11-
12-
namespace LIBC_NAMESPACE {
9+
#include "libc_errno.h"
1310

1411
#ifdef LIBC_TARGET_ARCH_IS_GPU
15-
struct ErrnoConsumer {
16-
void operator=(int) {}
17-
};
18-
#endif
12+
// LIBC_THREAD_LOCAL on GPU currently does nothing. So essentially this is just
13+
// a global errno for gpu to use for now.
14+
extern "C" {
15+
LIBC_THREAD_LOCAL int __llvmlibc_gpu_errno;
16+
}
1917

18+
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_gpu_errno = a; }
19+
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_gpu_errno; }
20+
21+
#elif !defined(LIBC_COPT_PUBLIC_PACKAGING)
22+
// This mode is for unit testing. We just use our internal errno.
23+
LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
24+
25+
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_internal_errno = a; }
26+
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_internal_errno; }
27+
28+
#elif defined(LIBC_FULL_BUILD)
29+
// This mode is for public libc archive, hermetic, and integration tests.
30+
// In full build mode, we provide the errno storage ourselves.
2031
extern "C" {
21-
#ifdef LIBC_COPT_PUBLIC_PACKAGING
22-
// TODO: Declare __llvmlibc_errno only under LIBC_COPT_PUBLIC_PACKAGING and
23-
// __llvmlibc_internal_errno otherwise.
24-
// In overlay mode, this will be an unused thread local variable as libc_errno
25-
// will resolve to errno from the system libc's errno.h. In full build mode
26-
// however, libc_errno will resolve to this thread local variable via the errno
27-
// macro defined in LLVM libc's public errno.h header file.
28-
// TODO: Use a macro to distinguish full build and overlay build which can be
29-
// used to exclude __llvmlibc_errno under overlay build.
30-
#ifdef LIBC_TARGET_ARCH_IS_GPU
31-
ErrnoConsumer __llvmlibc_errno;
32-
#else
3332
LIBC_THREAD_LOCAL int __llvmlibc_errno;
34-
#endif // LIBC_TARGET_ARCH_IS_GPU
33+
}
34+
35+
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
36+
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_errno; }
37+
3538
#else
36-
LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
37-
#endif
38-
} // extern "C"
39+
// In overlay mode, we simply use the system errno.
40+
#include <errno.h>
41+
42+
void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
43+
LIBC_NAMESPACE::Errno::operator int() { return errno; }
44+
45+
#endif // LIBC_FULL_BUILD
3946

40-
} // namespace LIBC_NAMESPACE
47+
// Define the global `libc_errno` instance.
48+
LIBC_NAMESPACE::Errno libc_errno;

libc/src/errno/libc_errno.h

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===-- Implementation header for errno -------------------------*- C++ -*-===//
1+
//===-- Implementation header for libc_errno --------------------*- C++ -*-===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -12,45 +12,35 @@
1212
#include "src/__support/macros/attributes.h"
1313
#include "src/__support/macros/properties/architectures.h"
1414

15+
// TODO: https://github.com/llvm/llvm-project/issues/80172
16+
// Separate just the definition of errno numbers in
17+
// include/llvm-libc-macros/* and only include that instead of the system
18+
// <errno.h>.
1519
#include <errno.h>
1620

17-
// If we are targeting the GPU we currently don't support 'errno'. We simply
18-
// consume it.
19-
#ifdef LIBC_TARGET_ARCH_IS_GPU
20-
namespace LIBC_NAMESPACE {
21-
struct ErrnoConsumer {
22-
void operator=(int) {}
23-
};
24-
} // namespace LIBC_NAMESPACE
25-
#endif
26-
27-
// All of the libc runtime and test code should use the "libc_errno" macro. They
28-
// should not refer to the "errno" macro directly.
29-
#ifdef LIBC_COPT_PUBLIC_PACKAGING
30-
#ifdef LIBC_TARGET_ARCH_IS_GPU
31-
extern "C" LIBC_NAMESPACE::ErrnoConsumer __llvmlibc_errno;
32-
#define libc_errno __llvmlibc_errno
33-
#else
34-
// This macro will resolve to errno from the errno.h file included above. Under
35-
// full build, this will be LLVM libc's errno. In overlay build, it will be
36-
// system libc's errno.
37-
#define libc_errno errno
38-
#endif
39-
#else
40-
namespace LIBC_NAMESPACE {
21+
// This header is to be consumed by internal implementations, in which all of
22+
// them should refer to `libc_errno` instead of using `errno` directly from
23+
// <errno.h> header.
4124

42-
// TODO: On the GPU build this will be mapped to a single global value. We need
43-
// to ensure that tests are not run with multiple threads that depend on errno
44-
// until we have true 'thread_local' support on the GPU.
45-
extern "C" LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
25+
// Unit and hermetic tests should:
26+
// - #include "src/errno/libc_errno.h"
27+
// - NOT #include <errno.h>
28+
// - Only use `libc_errno` in the code
29+
// - Depend on libc.src.errno.errno
4630

47-
// TODO: After all of libc/src and libc/test are switched over to use
48-
// libc_errno, this header file will be "shipped" via an add_entrypoint_object
49-
// target. At which point libc_errno, should point to __llvmlibc_internal_errno
50-
// if LIBC_COPT_PUBLIC_PACKAGING is not defined.
51-
#define libc_errno LIBC_NAMESPACE::__llvmlibc_internal_errno
31+
// Integration tests should:
32+
// - NOT #include "src/errno/libc_errno.h"
33+
// - #include <errno.h>
34+
// - Use regular `errno` in the code
35+
// - Still depend on libc.src.errno.errno
5236

37+
namespace LIBC_NAMESPACE {
38+
struct Errno {
39+
void operator=(int);
40+
operator int();
41+
};
5342
} // namespace LIBC_NAMESPACE
54-
#endif
43+
44+
extern LIBC_NAMESPACE::Errno libc_errno;
5545

5646
#endif // LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H

libc/test/integration/startup/linux/tls_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ TEST_MAIN(int argc, char **argv, char **envp) {
2828
// set in errno. Since errno is implemented using a thread
2929
// local var, this helps us test setting of errno and
3030
// reading it back.
31-
ASSERT_TRUE(libc_errno == 0);
31+
ASSERT_ERRNO_SUCCESS();
3232
void *addr = LIBC_NAMESPACE::mmap(nullptr, 0, PROT_READ,
3333
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3434
ASSERT_TRUE(addr == MAP_FAILED);
35-
ASSERT_TRUE(libc_errno == EINVAL);
35+
ASSERT_ERRNO_SUCCESS();
3636

3737
return 0;
3838
}

libc/test/src/errno/errno_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
TEST(LlvmLibcErrnoTest, Basic) {
1313
int test_val = 123;
1414
libc_errno = test_val;
15-
ASSERT_EQ(test_val, libc_errno);
15+
ASSERT_ERRNO_EQ(test_val);
1616
}

libc/test/src/stdlib/StrtolTest.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,7 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test {
331331
((is_signed_v<ReturnT> && sizeof(ReturnT) == 4)
332332
? T_MAX
333333
: ReturnT(0xFFFFFFFF)));
334-
ASSERT_EQ(libc_errno,
335-
is_signed_v<ReturnT> && sizeof(ReturnT) == 4 ? ERANGE : 0);
334+
ASSERT_ERRNO_EQ(is_signed_v<ReturnT> && sizeof(ReturnT) == 4 ? ERANGE : 0);
336335
EXPECT_EQ(str_end - max_32_bit_value, ptrdiff_t(10));
337336

338337
const char *negative_max_32_bit_value = "-0xFFFFFFFF";
@@ -341,8 +340,7 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test {
341340
((is_signed_v<ReturnT> && sizeof(ReturnT) == 4)
342341
? T_MIN
343342
: -ReturnT(0xFFFFFFFF)));
344-
ASSERT_EQ(libc_errno,
345-
is_signed_v<ReturnT> && sizeof(ReturnT) == 4 ? ERANGE : 0);
343+
ASSERT_ERRNO_EQ(is_signed_v<ReturnT> && sizeof(ReturnT) == 4 ? ERANGE : 0);
346344
EXPECT_EQ(str_end - negative_max_32_bit_value, ptrdiff_t(11));
347345

348346
// Max size for signed 32 bit numbers
@@ -368,8 +366,7 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test {
368366
(is_signed_v<ReturnT> || sizeof(ReturnT) < 8
369367
? T_MAX
370368
: ReturnT(0xFFFFFFFFFFFFFFFF)));
371-
ASSERT_EQ(libc_errno,
372-
(is_signed_v<ReturnT> || sizeof(ReturnT) < 8 ? ERANGE : 0));
369+
ASSERT_ERRNO_EQ((is_signed_v<ReturnT> || sizeof(ReturnT) < 8 ? ERANGE : 0));
373370
EXPECT_EQ(str_end - max_64_bit_value, ptrdiff_t(18));
374371

375372
// See the end of CleanBase10Decode for an explanation of how this large
@@ -381,8 +378,7 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::Test {
381378
(is_signed_v<ReturnT>
382379
? T_MIN
383380
: (sizeof(ReturnT) < 8 ? T_MAX : -ReturnT(0xFFFFFFFFFFFFFFFF))));
384-
ASSERT_EQ(libc_errno,
385-
(is_signed_v<ReturnT> || sizeof(ReturnT) < 8 ? ERANGE : 0));
381+
ASSERT_ERRNO_EQ((is_signed_v<ReturnT> || sizeof(ReturnT) < 8 ? ERANGE : 0));
386382
EXPECT_EQ(str_end - negative_max_64_bit_value, ptrdiff_t(19));
387383

388384
// Max size for signed 64 bit numbers

libc/test/src/sys/mman/linux/madvise_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ TEST(LlvmLibcMadviseTest, NoError) {
2323
libc_errno = 0;
2424
void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ,
2525
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
26-
EXPECT_EQ(0, libc_errno);
26+
ASSERT_ERRNO_SUCCESS();
2727
EXPECT_NE(addr, MAP_FAILED);
2828

2929
EXPECT_THAT(LIBC_NAMESPACE::madvise(addr, alloc_size, MADV_RANDOM),

libc/test/src/sys/mman/linux/mlock_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ TEST(LlvmLibcMlockTest, InvalidFlag) {
123123
libc_errno = 0;
124124
void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ,
125125
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
126-
EXPECT_EQ(0, libc_errno);
126+
ASSERT_ERRNO_SUCCESS();
127127
EXPECT_NE(addr, MAP_FAILED);
128128

129129
// Invalid mlock2 flags.

libc/test/src/sys/mman/linux/mmap_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ TEST(LlvmLibcMMapTest, NoError) {
2222
libc_errno = 0;
2323
void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ,
2424
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
25-
EXPECT_EQ(0, libc_errno);
25+
ASSERT_ERRNO_SUCCESS();
2626
EXPECT_NE(addr, MAP_FAILED);
2727

2828
int *array = reinterpret_cast<int *>(addr);

0 commit comments

Comments
 (0)