diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -17,6 +17,8 @@ libc.src.ctype.tolower libc.src.ctype.toupper + libc.src.errno.errno + # fcntl.h entrypoints libc.src.fcntl.creat libc.src.fcntl.open diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -151,6 +151,7 @@ DEF_FILE errno.h.def GEN_HDR errno.h DEPENDS + .llvm_libc_common_h .llvm-libc-macros.generic_error_number_macros ) diff --git a/libc/include/errno.h.def b/libc/include/errno.h.def --- a/libc/include/errno.h.def +++ b/libc/include/errno.h.def @@ -43,7 +43,9 @@ #include #endif +__BEGIN_C_DECLS extern _Thread_local int __llvmlibc_errno; +__END_C_DECLS #define errno __llvmlibc_errno #endif // LLVM_LIBC_ERRNO_H diff --git a/libc/src/errno/CMakeLists.txt b/libc/src/errno/CMakeLists.txt --- a/libc/src/errno/CMakeLists.txt +++ b/libc/src/errno/CMakeLists.txt @@ -1,17 +1,11 @@ -if (LLVM_LIBC_FULL_BUILD) -add_object_library( +add_entrypoint_object( errno SRCS - errno.cpp + libc_errno.cpp HDRS - llvmlibc_errno.h + libc_errno.h + DEPENDS + libc.include.errno + COMPILE_OPTIONS + -fomit-frame-pointer ) -else() -add_object_library( - errno - SRCS - dummy_errno.cpp - HDRS - dummy_errno.h -) -endif() diff --git a/libc/src/errno/errno.cpp b/libc/src/errno/errno.cpp deleted file mode 100644 --- a/libc/src/errno/errno.cpp +++ /dev/null @@ -1,9 +0,0 @@ -//===-- Implementation of __errno_location --------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -thread_local int __llvmlibc_errno = 0; diff --git a/libc/src/errno/libc_errno.h b/libc/src/errno/libc_errno.h new file mode 100644 --- /dev/null +++ b/libc/src/errno/libc_errno.h @@ -0,0 +1,28 @@ +//===-- 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_LLVMLIBC_ERRNO_H +#define LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H + +#include + +// Internal code (the libc runtime code as well as unit tests) should use this +// and not use the errno macro from the public errno.h header. +#ifdef LIBC_COPT_PUBLIC_PACKAGING +// This macro will resolve to errno from the errno.h file included above. Under +// full build, this will be LLVM libc's errno. In overlay build, it will be +// system libc's errno. +#define libc_errno errno +#else +namespace __llvm_libc { +extern "C" thread_local int __llvmlibc_internal_errno; +} // namespace __llvm_libc +#define libc_errno __llvm_libc::__llvmlibc_internal_errno +#endif + +#endif // LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H diff --git a/libc/src/errno/libc_errno.cpp b/libc/src/errno/libc_errno.cpp new file mode 100644 --- /dev/null +++ b/libc/src/errno/libc_errno.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of errno -------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +namespace __llvm_libc { + +extern "C" { +#ifdef LIBC_COPT_PUBLIC_PACKAGING +// In overlay mode, this will be an unused thread local variable as libc_errno +// will resolve to errno from the system libc's errno.h. In full build mode +// however, libc_errno will resolve to this thread local variable via the errno +// macro defined in LLVM libc's public errno.h header file. +// TODO: Use a macro to distinguish full build and overlay build which can be +// used to exclude __llvmlibc_errno under overlay build. +thread_local int __llvmlibc_errno; +#else +thread_local int __llvmlibc_internal_errno; +#endif +} // extern "C" + +} // namespace __llvm_libc diff --git a/libc/src/errno/llvmlibc_errno.h b/libc/src/errno/llvmlibc_errno.h deleted file mode 100644 --- a/libc/src/errno/llvmlibc_errno.h +++ /dev/null @@ -1,17 +0,0 @@ -//===-- 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_LLVMLIBC_ERRNO_H -#define LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H - -// Internal code should use this and not use the errno macro from the -// public header. -extern thread_local int __llvmlibc_errno; -#define llvmlibc_errno __llvmlibc_errno - -#endif // LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H diff --git a/libc/src/math/generic/exp2f.cpp b/libc/src/math/generic/exp2f.cpp --- a/libc/src/math/generic/exp2f.cpp +++ b/libc/src/math/generic/exp2f.cpp @@ -14,8 +14,7 @@ #include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY - -#include +#include "src/errno/libc_errno.h" #include "explogxf.h" @@ -48,7 +47,7 @@ if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); - errno = ERANGE; + libc_errno = ERANGE; } // x is +inf or nan return x + FPBits::inf().get_val(); @@ -64,7 +63,7 @@ if (fputil::get_round() == FE_UPWARD) return FPBits(FPBits::MIN_SUBNORMAL).get_val(); if (x != 0.0f) - errno = ERANGE; + libc_errno = ERANGE; return 0.0f; } } diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h --- a/libc/src/time/time_utils.h +++ b/libc/src/time/time_utils.h @@ -14,7 +14,7 @@ #include "include/errno.h" #include "src/__support/common.h" -#include "src/errno/llvmlibc_errno.h" +#include "src/errno/libc_errno.h" #include "src/time/mktime.h" #include @@ -86,11 +86,11 @@ // POSIX.1-2017 requires this. LIBC_INLINE time_t out_of_range() { - llvmlibc_errno = EOVERFLOW; + libc_errno = EOVERFLOW; return static_cast(-1); } -LIBC_INLINE void invalid_value() { llvmlibc_errno = EINVAL; } +LIBC_INLINE void invalid_value() { libc_errno = EINVAL; } LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer, size_t bufferLength) { diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt --- a/libc/test/UnitTest/CMakeLists.txt +++ b/libc/test/UnitTest/CMakeLists.txt @@ -33,11 +33,12 @@ FPMatcher.h ) target_include_directories(LibcFPTestHelpers PUBLIC ${LIBC_SOURCE_DIR}) -target_link_libraries(LibcFPTestHelpers LibcUnitTest libc_test_utils) +target_link_libraries(LibcFPTestHelpers LibcUnitTest libc_test_utils libc.src.errno.errno.__internal__) add_dependencies( LibcFPTestHelpers LibcUnitTest libc.test.UnitTest.string_utils + libc.src.errno.errno.__internal__ libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.fenv_impl ) diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -11,10 +11,10 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" #include "utils/testutils/RoundingModeUtils.h" -#include #include namespace __llvm_libc { @@ -106,8 +106,8 @@ #define EXPECT_MATH_ERRNO(expected) \ do { \ if (math_errhandling & MATH_ERRNO) { \ - int actual = errno; \ - errno = 0; \ + int actual = libc_errno; \ + libc_errno = 0; \ EXPECT_EQ(actual, expected); \ } \ } while (0) @@ -115,8 +115,8 @@ #define ASSERT_MATH_ERRNO(expected) \ do { \ if (math_errhandling & MATH_ERRNO) { \ - int actual = errno; \ - errno = 0; \ + int actual = libc_errno; \ + libc_errno = 0; \ ASSERT_EQ(actual, expected); \ } \ } while (0) diff --git a/libc/test/src/errno/CMakeLists.txt b/libc/test/src/errno/CMakeLists.txt --- a/libc/test/src/errno/CMakeLists.txt +++ b/libc/test/src/errno/CMakeLists.txt @@ -1,7 +1,3 @@ -if(NOT LLVM_LIBC_FULL_BUILD) - return() -endif() - add_libc_testsuite(libc_errno_unittests) add_libc_unittest( @@ -11,5 +7,6 @@ SRCS errno_test.cpp DEPENDS + libc.include.errno libc.src.errno.errno ) diff --git a/libc/test/src/errno/errno_test.cpp b/libc/test/src/errno/errno_test.cpp --- a/libc/test/src/errno/errno_test.cpp +++ b/libc/test/src/errno/errno_test.cpp @@ -6,11 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "src/errno/llvmlibc_errno.h" +#include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" TEST(LlvmLibcErrnoTest, Basic) { int test_val = 123; - llvmlibc_errno = test_val; - ASSERT_EQ(test_val, llvmlibc_errno); + libc_errno = test_val; + ASSERT_EQ(test_val, libc_errno); } diff --git a/libc/test/src/math/exp2f_test.cpp b/libc/test/src/math/exp2f_test.cpp --- a/libc/test/src/math/exp2f_test.cpp +++ b/libc/test/src/math/exp2f_test.cpp @@ -8,6 +8,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/errno/libc_errno.h" #include "src/math/exp2f.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" @@ -22,7 +23,7 @@ DECLARE_SPECIAL_CONSTANTS(float) TEST(LlvmLibcExp2fTest, SpecialNumbers) { - errno = 0; + libc_errno = 0; EXPECT_FP_EQ(aNaN, __llvm_libc::exp2f(aNaN)); EXPECT_MATH_ERRNO(0); @@ -41,7 +42,7 @@ } TEST(LlvmLibcExp2fTest, Overflow) { - errno = 0; + libc_errno = 0; EXPECT_FP_EQ(inf, __llvm_libc::exp2f(float(FPBits(0x7f7fffffU)))); EXPECT_MATH_ERRNO(ERANGE); @@ -69,7 +70,7 @@ 0xc3150000U, /*-0x1.2ap+7f*/ }; for (int i = 0; i < N; ++i) { - errno = 0; + libc_errno = 0; float x = float(FPBits(INPUTS[i])); EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, __llvm_libc::exp2f(x), 0.5); @@ -78,7 +79,7 @@ } TEST(LlvmLibcExp2fTest, Underflow) { - errno = 0; + libc_errno = 0; EXPECT_FP_EQ(0.0f, __llvm_libc::exp2f(float(FPBits(0xff7fffffU)))); EXPECT_MATH_ERRNO(ERANGE); @@ -105,14 +106,14 @@ float x = float(FPBits(v)); if (isnan(x) || isinf(x)) continue; - errno = 0; + libc_errno = 0; float result = __llvm_libc::exp2f(x); // If the computation resulted in an error or did not produce valid result // in the single-precision floating point range, then ignore comparing with // MPFR result as MPFR can still produce valid results because of its // wider precision. - if (isnan(result) || isinf(result) || errno != 0) + if (isnan(result) || isinf(result) || libc_errno != 0) continue; ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x, __llvm_libc::exp2f(x), 0.5);