1 | //===------------------------ memory_resource.cpp -------------------------===// |
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 "experimental/memory_resource" |
10 | |
11 | #ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER |
12 | #include "atomic" |
13 | #elif !defined(_LIBCPP_HAS_NO_THREADS) |
14 | #include "mutex" |
15 | #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) |
16 | #pragma comment(lib, "pthread") |
17 | #endif |
18 | #endif |
19 | |
20 | _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR |
21 | |
22 | // memory_resource |
23 | |
24 | //memory_resource::~memory_resource() {} |
25 | |
26 | // new_delete_resource() |
27 | |
28 | class _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp |
29 | : public memory_resource |
30 | { |
31 | void *do_allocate(size_t size, size_t align) override { |
32 | #ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION |
33 | if (__is_overaligned_for_new(align)) |
34 | __throw_bad_alloc(); |
35 | #endif |
36 | return _VSTD::__libcpp_allocate(size, align); |
37 | } |
38 | |
39 | void do_deallocate(void *p, size_t n, size_t align) override { |
40 | _VSTD::__libcpp_deallocate(p, n, align); |
41 | } |
42 | |
43 | bool do_is_equal(memory_resource const & other) const _NOEXCEPT override |
44 | { return &other == this; } |
45 | |
46 | public: |
47 | ~__new_delete_memory_resource_imp() override = default; |
48 | }; |
49 | |
50 | // null_memory_resource() |
51 | |
52 | class _LIBCPP_TYPE_VIS __null_memory_resource_imp |
53 | : public memory_resource |
54 | { |
55 | public: |
56 | ~__null_memory_resource_imp() = default; |
57 | |
58 | protected: |
59 | virtual void* do_allocate(size_t, size_t) { |
60 | __throw_bad_alloc(); |
61 | } |
62 | virtual void do_deallocate(void *, size_t, size_t) {} |
63 | virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT |
64 | { return &__other == this; } |
65 | }; |
66 | |
67 | namespace { |
68 | |
69 | union ResourceInitHelper { |
70 | struct { |
71 | __new_delete_memory_resource_imp new_delete_res; |
72 | __null_memory_resource_imp null_res; |
73 | } resources; |
74 | char dummy; |
75 | _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {} |
76 | ~ResourceInitHelper() {} |
77 | }; |
78 | |
79 | // Detect if the init_priority attribute is supported. |
80 | #if (defined(_LIBCPP_COMPILER_GCC) && defined(__APPLE__)) \ |
81 | || defined(_LIBCPP_COMPILER_MSVC) |
82 | // GCC on Apple doesn't support the init priority attribute, |
83 | // and MSVC doesn't support any GCC attributes. |
84 | # define _LIBCPP_INIT_PRIORITY_MAX |
85 | #else |
86 | # define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101))) |
87 | #endif |
88 | |
89 | // When compiled in C++14 this initialization should be a constant expression. |
90 | // Only in C++11 is "init_priority" needed to ensure initialization order. |
91 | #if _LIBCPP_STD_VER > 11 |
92 | _LIBCPP_SAFE_STATIC |
93 | #endif |
94 | ResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX; |
95 | |
96 | } // end namespace |
97 | |
98 | |
99 | memory_resource * new_delete_resource() _NOEXCEPT { |
100 | return &res_init.resources.new_delete_res; |
101 | } |
102 | |
103 | memory_resource * null_memory_resource() _NOEXCEPT { |
104 | return &res_init.resources.null_res; |
105 | } |
106 | |
107 | // default_memory_resource() |
108 | |
109 | static memory_resource * |
110 | __default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT |
111 | { |
112 | #ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER |
113 | _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res = |
114 | ATOMIC_VAR_INIT(&res_init.resources.new_delete_res); |
115 | if (set) { |
116 | new_res = new_res ? new_res : new_delete_resource(); |
117 | // TODO: Can a weaker ordering be used? |
118 | return _VSTD::atomic_exchange_explicit( |
119 | &__res, new_res, memory_order_acq_rel); |
120 | } |
121 | else { |
122 | return _VSTD::atomic_load_explicit( |
123 | &__res, memory_order_acquire); |
124 | } |
125 | #elif !defined(_LIBCPP_HAS_NO_THREADS) |
126 | _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res; |
127 | static mutex res_lock; |
128 | if (set) { |
129 | new_res = new_res ? new_res : new_delete_resource(); |
130 | lock_guard<mutex> guard(res_lock); |
131 | memory_resource * old_res = res; |
132 | res = new_res; |
133 | return old_res; |
134 | } else { |
135 | lock_guard<mutex> guard(res_lock); |
136 | return res; |
137 | } |
138 | #else |
139 | _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res; |
140 | if (set) { |
141 | new_res = new_res ? new_res : new_delete_resource(); |
142 | memory_resource * old_res = res; |
143 | res = new_res; |
144 | return old_res; |
145 | } else { |
146 | return res; |
147 | } |
148 | #endif |
149 | } |
150 | |
151 | memory_resource * get_default_resource() _NOEXCEPT |
152 | { |
153 | return __default_memory_resource(); |
154 | } |
155 | |
156 | memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT |
157 | { |
158 | return __default_memory_resource(true, __new_res); |
159 | } |
160 | |
161 | _LIBCPP_END_NAMESPACE_LFTS_PMR |
162 | |