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
operator =(int)56 void Errno::operator=(int) {}
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