Skip to content

Commit 816e80c

Browse files
authored
Merge pull request managarm#1766 from no92/libc++-cxa-guard
options/internal: initialize `GlobalConfig` while avoiding cxa_guard
2 parents 6c1d0d6 + 14b0c3e commit 816e80c

11 files changed

Lines changed: 98 additions & 110 deletions

File tree

options/ansi/generic/environment.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ size_t find_environ_index(frg::string_view name) {
3434
return -1;
3535
}
3636

37+
struct EnvironmentVector {
38+
EnvironmentVector() : vector{getAllocator()} {}
39+
frg::vector<char *, MemoryAllocator> vector;
40+
};
41+
42+
constinit mlibc::lazy_eternal<EnvironmentVector> global_vector;
43+
3744
// Environment vector that is mutated by putenv() and setenv().
38-
// Cannot be global as it is accessed during library initialization.
3945
frg::vector<char *, MemoryAllocator> &get_vector() {
40-
static frg::vector<char *, MemoryAllocator> vector{getAllocator()};
41-
return vector;
46+
return global_vector.get().vector;
4247
}
4348

4449
void update_vector() {

options/ansi/generic/file-io.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ namespace {
4444
// The maximum number of characters we permit the user to ungetc.
4545
constexpr size_t ungetBufferSize = 8;
4646

47+
constinit mlibc::lazy_eternal<file_list> global_file_list_instance;
48+
4749
// List of files that will be flushed before exit().
4850
file_list &global_file_list() {
49-
static frg::eternal<file_list> list;
50-
return list.get();
51+
return global_file_list_instance.get();
5152
};
5253
} // namespace
5354

options/glibc/generic/shadow.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,17 @@ void endspent(void) {
227227
mlibc::infoLogger() << "mlibc: endspent is a stub" << frg::endlog;
228228
}
229229

230+
struct SgetspentBuffer {
231+
SgetspentBuffer() : string{getAllocator()} {}
232+
frg::string<MemoryAllocator> string;
233+
};
234+
235+
static constinit mlibc::lazy_eternal<SgetspentBuffer> globalSgetspentBuffer;
236+
230237
struct spwd *sgetspent(const char *s) {
231-
static frg::string<MemoryAllocator> buffer{getAllocator()};
232238
static struct spwd sp;
233239

240+
auto &buffer = globalSgetspentBuffer.get().string;
234241
buffer = {s, getAllocator()};
235242

236243
if (__parsespent(buffer.data(), &sp) == 0)

options/internal/gcc/guard-abi.cpp

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,89 +6,15 @@
66
#include <mlibc/debug.hpp>
77
#include <mlibc/tid.hpp>
88

9-
namespace {
10-
11-
// Itanium ABI static initialization guard.
12-
struct Guard {
13-
static constexpr uint32_t waitersBit = 0x80000000;
14-
static constexpr uint32_t ownerMask = 0x3FFFFFFF;
15-
16-
void lock() {
17-
uint32_t tid = mlibc::this_tid();
18-
uint32_t expected = 0;
19-
20-
while (true) {
21-
if (!expected) {
22-
if (__atomic_compare_exchange_n(
23-
&mutex, &expected, tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE
24-
))
25-
return;
26-
} else {
27-
if ((expected & ownerMask) == tid)
28-
mlibc::panicLogger()
29-
<< "mlibc: __cxa_guard_acquire deadlock detected!" << frg::endlog;
30-
31-
if (expected & waitersBit) {
32-
int e = mlibc::sysdep<FutexWait>((int *)&mutex, expected, nullptr);
33-
if (e && e != EAGAIN && e != EINTR)
34-
mlibc::panicLogger()
35-
<< "sys_futex_wait() failed with error code " << e << frg::endlog;
36-
expected = 0;
37-
} else {
38-
uint32_t desired = expected | waitersBit;
39-
if (__atomic_compare_exchange_n(
40-
&mutex, &expected, desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED
41-
))
42-
expected = desired;
43-
}
44-
}
45-
}
46-
}
47-
48-
void unlock() {
49-
uint32_t state = __atomic_exchange_n(&mutex, 0, __ATOMIC_RELEASE);
50-
__ensure((state & ownerMask) == mlibc::this_tid());
51-
if(state & waitersBit)
52-
mlibc::sysdep<FutexWake>((int *)&mutex, true);
53-
}
54-
55-
// the first byte's meaning is fixed by the ABI.
56-
// it indicates whether initialization has already been completed.
57-
uint8_t complete;
58-
// padding to ensure correct alignment on certain platforms.
59-
uint8_t padding[3];
60-
61-
// we use some of the remaining bytes to implement a mutex.
62-
uint32_t mutex;
63-
};
64-
65-
static_assert(sizeof(Guard) == sizeof(int64_t));
66-
67-
} // namespace
68-
699
extern "C" [[ gnu::visibility("hidden") ]] void __cxa_pure_virtual() {
7010
mlibc::panicLogger() << "mlibc: Pure virtual function called from IP "
7111
<< (void *)__builtin_return_address(0) << frg::endlog;
7212
}
7313

74-
extern "C" [[ gnu::visibility("hidden") ]] int __cxa_guard_acquire(int64_t *ptr) {
75-
auto guard = reinterpret_cast<Guard *>(ptr);
76-
guard->lock();
77-
// relaxed ordering is sufficient because
78-
// Guard::complete is only modified while the mutex is held.
79-
if(__atomic_load_n(&guard->complete, __ATOMIC_RELAXED)) {
80-
guard->unlock();
81-
return 0;
82-
}else{
83-
return 1;
84-
}
85-
}
86-
87-
extern "C" [[ gnu::visibility("hidden") ]] void __cxa_guard_release(int64_t *ptr) {
88-
auto guard = reinterpret_cast<Guard *>(ptr);
89-
// do a store-release so that compiler generated code can skip calling
90-
// __cxa_guard_acquire by doing a load-acquire on Guard::complete.
91-
__atomic_store_n(&guard->complete, 1, __ATOMIC_RELEASE);
92-
guard->unlock();
93-
}
14+
static const char __poison_cxa_guard_acquire[]
15+
__attribute__((used, section(".gnu.warning.__cxa_guard_acquire"))) =
16+
"mlibc cannot use static singletons, use lazy_eternal instead";
9417

18+
static const char __poison_cxa_guard_release[]
19+
__attribute__((used, section(".gnu.warning.__cxa_guard_release"))) =
20+
"mlibc cannot use static singletons, use lazy_eternal instead";

options/internal/generic/allocator.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@
1313
// Globals
1414
// --------------------------------------------------------
1515

16+
struct AllocatorPackage {
17+
AllocatorPackage()
18+
: heap{virtualAllocator}, singleton{&heap} {}
19+
20+
VirtualAllocator virtualAllocator;
21+
MemoryPool heap;
22+
MemoryAllocator singleton;
23+
};
24+
25+
constinit mlibc::lazy_eternal<AllocatorPackage> global_allocator_package;
26+
1627
MemoryAllocator &getAllocator() {
17-
// use frg::eternal to prevent a call to __cxa_atexit().
18-
// this is necessary because __cxa_atexit() call this function.
19-
static frg::eternal<VirtualAllocator> virtualAllocator;
20-
static frg::eternal<MemoryPool> heap{virtualAllocator.get()};
21-
static frg::eternal<MemoryAllocator> singleton{&heap.get()};
22-
return singleton.get();
28+
return global_allocator_package.get().singleton;
2329
}
2430

2531
// --------------------------------------------------------
@@ -199,11 +205,10 @@ size_t MemoryAllocator::get_size(void *ptr) {
199205
return meta->allocatedSize;
200206
}
201207

208+
constinit mlibc::lazy_eternal<MemoryAllocator> global_debug_allocator;
209+
202210
MemoryAllocator &getAllocator() {
203-
// use frg::eternal to prevent a call to __cxa_atexit().
204-
// this is necessary because __cxa_atexit() call this function.
205-
static frg::eternal<MemoryAllocator> singleton{};
206-
return singleton.get();
211+
return global_debug_allocator.get();
207212
}
208213

209214
#endif /* !MLIBC_DEBUG_ALLOCATOR */

options/internal/generic/charcode.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <array>
22
#include <bits/ensure.h>
33
#include <frg/string.hpp>
4+
#include <mlibc/allocator.hpp>
45
#include <mlibc/charcode.hpp>
56
#include <mlibc/debug.hpp>
67

@@ -312,9 +313,10 @@ struct polymorphic_charcode_adapter : polymorphic_charcode {
312313
}
313314
};
314315

316+
constinit mlibc::lazy_eternal<polymorphic_charcode_adapter<utf8_charcode>> global_charcode;
317+
315318
polymorphic_charcode *current_charcode() {
316-
static polymorphic_charcode_adapter<utf8_charcode> global_charcode;
317-
return &global_charcode;
319+
return &global_charcode.get();
318320
}
319321

320322
transcode_status wide_charcode::promote(wchar_t nc, codepoint &wc) {

options/internal/generic/global-config.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
#include <stdlib.h>
2-
#include <string.h>
2+
#include <mlibc/allocator.hpp>
33
#include <mlibc/global-config.hpp>
44

55
namespace mlibc {
66

7+
namespace {
8+
9+
constinit mlibc::lazy_eternal<GlobalConfig> globalConfigInstance;
10+
11+
} // namespace
12+
713
struct GlobalConfigGuard {
814
GlobalConfigGuard();
915
};
@@ -12,7 +18,7 @@ GlobalConfigGuard guard;
1218

1319
GlobalConfigGuard::GlobalConfigGuard() {
1420
// Force the config to be created during initialization of libc.so.
15-
mlibc::globalConfig();
21+
globalConfigInstance.get();
1622
}
1723

1824
static bool envEnabled(const char *env) {
@@ -29,4 +35,8 @@ GlobalConfig::GlobalConfig() {
2935
debugMonetaryLengths = envEnabled("MLIBC_DEBUG_MONETARY_LENGTHS");
3036
}
3137

38+
const GlobalConfig &globalConfig() {
39+
return globalConfigInstance.get();
40+
}
41+
3242
} // namespace mlibc

options/internal/include/mlibc/allocator.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <mlibc/lock.hpp>
55
#include <bits/ensure.h>
6+
#include <frg/manual_box.hpp>
67
#include <frg/slab.hpp>
78
#include <internal-config.h>
89

@@ -35,4 +36,34 @@ MemoryAllocator &getAllocator();
3536

3637
#endif // !MLIBC_DEBUG_ALLOCATOR
3738

39+
namespace mlibc {
40+
41+
template <typename T>
42+
struct lazy_eternal {
43+
constexpr lazy_eternal() = default;
44+
45+
template <typename Self>
46+
auto &get(this Self &self) {
47+
if (__atomic_load_n(&self.initialized_, __ATOMIC_ACQUIRE))
48+
return *self.box_.get();
49+
50+
{
51+
frg::unique_lock lock{self.lock_};
52+
if (!__atomic_load_n(&self.initialized_, __ATOMIC_RELAXED)) {
53+
self.box_.initialize();
54+
__atomic_store_n(&self.initialized_, 1, __ATOMIC_RELEASE);
55+
}
56+
}
57+
58+
return *self.box_.get();
59+
}
60+
61+
private:
62+
mutable uint32_t initialized_ = 0;
63+
mutable FutexLock lock_;
64+
mutable frg::manual_box<T> box_;
65+
};
66+
67+
} // namespace mlibc
68+
3869
#endif // MLIBC_FRIGG_ALLOC

options/internal/include/mlibc/global-config.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@ struct GlobalConfig {
1414
bool debugMonetaryLengths;
1515
};
1616

17-
inline const GlobalConfig &globalConfig() {
18-
static GlobalConfig cached;
19-
return cached;
20-
}
17+
const GlobalConfig &globalConfig();
2118

22-
}
19+
} // namespace mlibc
2320

2421
#endif // MLIBC_GLOBAL_CONFIG

options/internal/include/mlibc/lock.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
template<bool Recursive>
1616
struct alignas(4) FutexLockImpl {
17-
FutexLockImpl() : _state{0}, _recursion{0} { }
17+
constexpr FutexLockImpl() : _state{0}, _recursion{0} { }
1818

1919
FutexLockImpl(const FutexLockImpl &) = delete;
2020

0 commit comments

Comments
 (0)