Skip to content

Commit 28699e3

Browse files
authored
[libc] Update libc_errno to work correctly in both overlay and full build modes. (#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);

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

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

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ TEST(LlvmLibcPosixMadviseTest, 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_EQ(LIBC_NAMESPACE::posix_madvise(addr, alloc_size, POSIX_MADV_RANDOM),

libc/test/src/time/asctime_r_test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ static inline char *call_asctime_r(struct tm *tm_data, int year, int month,
2727
TEST(LlvmLibcAsctimeR, Nullptr) {
2828
char *result;
2929
result = LIBC_NAMESPACE::asctime_r(nullptr, nullptr);
30-
ASSERT_EQ(EINVAL, libc_errno);
30+
ASSERT_ERRNO_EQ(EINVAL);
3131
ASSERT_STREQ(nullptr, result);
3232

3333
char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
3434
result = LIBC_NAMESPACE::asctime_r(nullptr, buffer);
35-
ASSERT_EQ(EINVAL, libc_errno);
35+
ASSERT_ERRNO_EQ(EINVAL);
3636
ASSERT_STREQ(nullptr, result);
3737

3838
struct tm tm_data;
3939
result = LIBC_NAMESPACE::asctime_r(&tm_data, nullptr);
40-
ASSERT_EQ(EINVAL, libc_errno);
40+
ASSERT_ERRNO_EQ(EINVAL);
4141
ASSERT_STREQ(nullptr, result);
4242
}
4343

libc/test/src/time/asctime_test.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static inline char *call_asctime(struct tm *tm_data, int year, int month,
2222
TEST(LlvmLibcAsctime, Nullptr) {
2323
char *result;
2424
result = LIBC_NAMESPACE::asctime(nullptr);
25-
ASSERT_EQ(EINVAL, libc_errno);
25+
ASSERT_ERRNO_EQ(EINVAL);
2626
ASSERT_STREQ(nullptr, result);
2727
}
2828

@@ -40,7 +40,7 @@ TEST(LlvmLibcAsctime, InvalidWday) {
4040
0, // sec
4141
-1, // wday
4242
0); // yday
43-
ASSERT_EQ(EINVAL, libc_errno);
43+
ASSERT_ERRNO_EQ(EINVAL);
4444

4545
// Test with wday = 7.
4646
call_asctime(&tm_data,
@@ -52,7 +52,7 @@ TEST(LlvmLibcAsctime, InvalidWday) {
5252
0, // sec
5353
7, // wday
5454
0); // yday
55-
ASSERT_EQ(EINVAL, libc_errno);
55+
ASSERT_ERRNO_EQ(EINVAL);
5656
}
5757

5858
// Months are from January to December. Test passing invalid value in month.
@@ -69,7 +69,7 @@ TEST(LlvmLibcAsctime, InvalidMonth) {
6969
0, // sec
7070
4, // wday
7171
0); // yday
72-
ASSERT_EQ(EINVAL, libc_errno);
72+
ASSERT_ERRNO_EQ(EINVAL);
7373

7474
// Test with month = 13.
7575
call_asctime(&tm_data,
@@ -81,7 +81,7 @@ TEST(LlvmLibcAsctime, InvalidMonth) {
8181
0, // sec
8282
4, // wday
8383
0); // yday
84-
ASSERT_EQ(EINVAL, libc_errno);
84+
ASSERT_ERRNO_EQ(EINVAL);
8585
}
8686

8787
TEST(LlvmLibcAsctime, ValidWeekdays) {
@@ -209,6 +209,6 @@ TEST(LlvmLibcAsctime, Max64BitYear) {
209209
50, // sec
210210
2, // wday
211211
50); // yday
212-
ASSERT_EQ(EOVERFLOW, libc_errno);
212+
ASSERT_ERRNO_EQ(EOVERFLOW);
213213
ASSERT_STREQ(nullptr, result);
214214
}

0 commit comments

Comments
 (0)