Skip to content

Commit 34a5a50

Browse files
committed
Update libc_errno to work correctly for both overlay and full build modes.
1 parent e15ee80 commit 34a5a50

File tree

12 files changed

+90
-82
lines changed

12 files changed

+90
-82
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
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+
set(full_build_flag "")
6+
if(LLVM_LIBC_FULL_BUILD)
7+
set(full_build_flag "-DLIBC_FULL_BUILD")
8+
endif()
9+
110
add_entrypoint_object(
211
errno
312
SRCS
413
libc_errno.cpp
514
HDRS
615
libc_errno.h # Include this
16+
COMPILE_OPTIONS
17+
${full_build_flag}
718
DEPENDS
819
libc.include.errno
920
libc.src.__support.common

libc/src/errno/libc_errno.cpp

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,44 @@
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+
// If we are targeting the GPU we currently don't support 'errno'. We simply
13+
// consume it.
14+
void LIBC_NAMESPACE::Errno::operator=(int) {}
15+
LIBC_NAMESPACE::Errno::operator int() { return 0; }
16+
17+
#elif !defined(LIBC_COPT_PUBLIC_PACKAGING)
18+
// This mode is for unit testing. We just use our internal errno.
19+
LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
1920

21+
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_internal_errno = a; }
22+
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_internal_errno; }
23+
24+
#elif defined(LIBC_FULL_BUILD)
25+
// This mode is for public libc archive, hermetic, and integration tests.
26+
// In full build mode, we provide the errno storage ourselves.
2027
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
3328
LIBC_THREAD_LOCAL int __llvmlibc_errno;
34-
#endif // LIBC_TARGET_ARCH_IS_GPU
29+
}
30+
31+
void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
32+
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_errno; }
33+
3534
#else
36-
LIBC_THREAD_LOCAL int __llvmlibc_internal_errno;
37-
#endif
38-
} // extern "C"
35+
// In overlay mode, we simply use the system errno.
36+
#include <errno.h>
37+
38+
void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
39+
LIBC_NAMESPACE::Errno::operator int() { return errno; }
40+
41+
#endif // LIBC_FULL_BUILD
3942

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

libc/src/errno/libc_errno.h

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,34 @@
1212
#include "src/__support/macros/attributes.h"
1313
#include "src/__support/macros/properties/architectures.h"
1414

15+
// TODO: Separate just the definition of errno numbers in
16+
// include/llvm-libc-macros/* and only include that instead of the system
17+
// <errno.h>.
1518
#include <errno.h>
1619

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 {
20+
// This header is to be consumed by internal implementations, in which all of
21+
// them should refer to `libc_errno` instead of using `errno` directly from
22+
// <errno.h> header.
4123

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;
24+
// Unit and hermetic tests should:
25+
// - #include "src/errno/libc_errno.h"
26+
// - DO NOT #include <errno.h>
27+
// - Only use `libc_errno` in the code
28+
// - Depend on libc.src.errno.errno
4629

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
30+
// Integration tests should:
31+
// - DO NOT #include "src/errno/libc_errno.h"
32+
// - #include <errno.h>
33+
// - Use regular `errno` in the code
34+
// - Still depend on libc.src.errno.errno
5235

36+
namespace LIBC_NAMESPACE {
37+
struct Errno {
38+
void operator=(int);
39+
operator int();
40+
};
5341
} // namespace LIBC_NAMESPACE
54-
#endif
42+
43+
extern LIBC_NAMESPACE::Errno libc_errno;
5544

5645
#endif // LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H

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/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)