memory_resource.cpp revision 355940
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(__unix__) && defined(__ELF__) && defined(_LIBCPP_HAS_COMMENT_LIB_PRAGMA) 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 28class _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 46public: 47 ~__new_delete_memory_resource_imp() override = default; 48}; 49 50// null_memory_resource() 51 52class _LIBCPP_TYPE_VIS __null_memory_resource_imp 53 : public memory_resource 54{ 55public: 56 ~__null_memory_resource_imp() = default; 57 58protected: 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 67namespace { 68 69union 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 94ResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX; 95 96} // end namespace 97 98 99memory_resource * new_delete_resource() _NOEXCEPT { 100 return &res_init.resources.new_delete_res; 101} 102 103memory_resource * null_memory_resource() _NOEXCEPT { 104 return &res_init.resources.null_res; 105} 106 107// default_memory_resource() 108 109static 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::memory_order_acq_rel); 120 } 121 else { 122 return _VSTD::atomic_load_explicit( 123 &__res, memory_order::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 151memory_resource * get_default_resource() _NOEXCEPT 152{ 153 return __default_memory_resource(); 154} 155 156memory_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