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