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