1 //===-- Implementation of libc_errno --------------------------------------===// 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 #include "libc_errno.h" 10 #include "src/__support/macros/config.h" 11 12 // libc uses a fallback default value, either system or thread local. 13 #define LIBC_ERRNO_MODE_DEFAULT 0 14 // libc never stores a value; `errno` macro uses get link-time failure. 15 #define LIBC_ERRNO_MODE_UNDEFINED 1 16 // libc maintains per-thread state (requires C++ `thread_local` support). 17 #define LIBC_ERRNO_MODE_THREAD_LOCAL 2 18 // libc maintains shared state used by all threads, contrary to standard C 19 // semantics unless always single-threaded; nothing prevents data races. 20 #define LIBC_ERRNO_MODE_SHARED 3 21 // libc doesn't maintain any internal state, instead the embedder must define 22 // `int *__llvm_libc_errno(void);` C function. 23 #define LIBC_ERRNO_MODE_EXTERNAL 4 24 // libc uses system `<errno.h>` `errno` macro directly in the overlay mode; in 25 // fullbuild mode, effectively the same as `LIBC_ERRNO_MODE_EXTERNAL`. 26 #define LIBC_ERRNO_MODE_SYSTEM 5 27 28 #if !defined(LIBC_ERRNO_MODE) || LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_DEFAULT 29 #undef LIBC_ERRNO_MODE 30 #if defined(LIBC_FULL_BUILD) || !defined(LIBC_COPT_PUBLIC_PACKAGING) 31 #define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_THREAD_LOCAL 32 #else 33 #define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM 34 #endif 35 #endif // LIBC_ERRNO_MODE 36 37 #if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_DEFAULT && \ 38 LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_UNDEFINED && \ 39 LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_THREAD_LOCAL && \ 40 LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SHARED && \ 41 LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_EXTERNAL && \ 42 LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM 43 #error LIBC_ERRNO_MODE must be one of the following values: \ 44 LIBC_ERRNO_MODE_DEFAULT, \ 45 LIBC_ERRNO_MODE_UNDEFINED, \ 46 LIBC_ERRNO_MODE_THREAD_LOCAL, \ 47 LIBC_ERRNO_MODE_SHARED, \ 48 LIBC_ERRNO_MODE_EXTERNAL, \ 49 LIBC_ERRNO_MODE_SYSTEM 50 #endif 51 52 namespace LIBC_NAMESPACE_DECL { 53 54 #if LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_UNDEFINED 55 56 void Errno::operator=(int) {} 57 Errno::operator int() { return 0; } 58 59 #elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_THREAD_LOCAL 60 61 namespace { 62 LIBC_THREAD_LOCAL int thread_errno; 63 } 64 65 extern "C" int *__llvm_libc_errno() noexcept { return &thread_errno; } 66 67 void Errno::operator=(int a) { thread_errno = a; } 68 Errno::operator int() { return thread_errno; } 69 70 #elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SHARED 71 72 namespace { 73 int shared_errno; 74 } 75 76 extern "C" int *__llvm_libc_errno() noexcept { return &shared_errno; } 77 78 void Errno::operator=(int a) { shared_errno = a; } 79 Errno::operator int() { return shared_errno; } 80 81 #elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_EXTERNAL 82 83 void Errno::operator=(int a) { *__llvm_libc_errno() = a; } 84 Errno::operator int() { return *__llvm_libc_errno(); } 85 86 #elif LIBC_ERRNO_MODE == LIBC_ERRNO_MODE_SYSTEM 87 88 void Errno::operator=(int a) { errno = a; } 89 Errno::operator int() { return errno; } 90 91 #endif 92 93 // Define the global `libc_errno` instance. 94 Errno libc_errno; 95 96 } // namespace LIBC_NAMESPACE_DECL 97