1*c303c47eSjoerg //===------------------------ memory_resource.cpp -------------------------===//
2*c303c47eSjoerg //
3*c303c47eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c303c47eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*c303c47eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c303c47eSjoerg //
7*c303c47eSjoerg //===----------------------------------------------------------------------===//
8*c303c47eSjoerg 
9*c303c47eSjoerg #include "experimental/memory_resource"
10*c303c47eSjoerg 
11*c303c47eSjoerg #ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
12*c303c47eSjoerg #include "atomic"
13*c303c47eSjoerg #elif !defined(_LIBCPP_HAS_NO_THREADS)
14*c303c47eSjoerg #include "mutex"
15*c303c47eSjoerg #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
16*c303c47eSjoerg #pragma comment(lib, "pthread")
17*c303c47eSjoerg #endif
18*c303c47eSjoerg #endif
19*c303c47eSjoerg 
20*c303c47eSjoerg _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
21*c303c47eSjoerg 
22*c303c47eSjoerg // memory_resource
23*c303c47eSjoerg 
24*c303c47eSjoerg //memory_resource::~memory_resource() {}
25*c303c47eSjoerg 
26*c303c47eSjoerg // new_delete_resource()
27*c303c47eSjoerg 
28*c303c47eSjoerg class _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
29*c303c47eSjoerg     : public memory_resource
30*c303c47eSjoerg {
do_allocate(size_t size,size_t align)31*c303c47eSjoerg     void *do_allocate(size_t size, size_t align) override {
32*c303c47eSjoerg #ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
33*c303c47eSjoerg         if (__is_overaligned_for_new(align))
34*c303c47eSjoerg             __throw_bad_alloc();
35*c303c47eSjoerg #endif
36*c303c47eSjoerg         return _VSTD::__libcpp_allocate(size, align);
37*c303c47eSjoerg     }
38*c303c47eSjoerg 
do_deallocate(void * p,size_t n,size_t align)39*c303c47eSjoerg     void do_deallocate(void *p, size_t n, size_t align) override {
40*c303c47eSjoerg       _VSTD::__libcpp_deallocate(p, n, align);
41*c303c47eSjoerg     }
42*c303c47eSjoerg 
do_is_equal(memory_resource const & other) const43*c303c47eSjoerg     bool do_is_equal(memory_resource const & other) const noexcept override
44*c303c47eSjoerg         { return &other == this; }
45*c303c47eSjoerg 
46*c303c47eSjoerg public:
47*c303c47eSjoerg     ~__new_delete_memory_resource_imp() override = default;
48*c303c47eSjoerg };
49*c303c47eSjoerg 
50*c303c47eSjoerg // null_memory_resource()
51*c303c47eSjoerg 
52*c303c47eSjoerg class _LIBCPP_TYPE_VIS __null_memory_resource_imp
53*c303c47eSjoerg     : public memory_resource
54*c303c47eSjoerg {
55*c303c47eSjoerg public:
56*c303c47eSjoerg     ~__null_memory_resource_imp() = default;
57*c303c47eSjoerg 
58*c303c47eSjoerg protected:
do_allocate(size_t,size_t)59*c303c47eSjoerg     virtual void* do_allocate(size_t, size_t) {
60*c303c47eSjoerg         __throw_bad_alloc();
61*c303c47eSjoerg     }
do_deallocate(void *,size_t,size_t)62*c303c47eSjoerg     virtual void do_deallocate(void *, size_t, size_t) {}
do_is_equal(memory_resource const & __other) const63*c303c47eSjoerg     virtual bool do_is_equal(memory_resource const & __other) const noexcept
64*c303c47eSjoerg     { return &__other == this; }
65*c303c47eSjoerg };
66*c303c47eSjoerg 
67*c303c47eSjoerg namespace {
68*c303c47eSjoerg 
69*c303c47eSjoerg union ResourceInitHelper {
70*c303c47eSjoerg   struct {
71*c303c47eSjoerg     __new_delete_memory_resource_imp new_delete_res;
72*c303c47eSjoerg     __null_memory_resource_imp       null_res;
73*c303c47eSjoerg   } resources;
74*c303c47eSjoerg   char dummy;
ResourceInitHelper()75*c303c47eSjoerg   _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
~ResourceInitHelper()76*c303c47eSjoerg   ~ResourceInitHelper() {}
77*c303c47eSjoerg };
78*c303c47eSjoerg 
79*c303c47eSjoerg _LIBCPP_SAFE_STATIC ResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX;
80*c303c47eSjoerg 
81*c303c47eSjoerg } // end namespace
82*c303c47eSjoerg 
83*c303c47eSjoerg 
new_delete_resource()84*c303c47eSjoerg memory_resource * new_delete_resource() noexcept {
85*c303c47eSjoerg     return &res_init.resources.new_delete_res;
86*c303c47eSjoerg }
87*c303c47eSjoerg 
null_memory_resource()88*c303c47eSjoerg memory_resource * null_memory_resource() noexcept {
89*c303c47eSjoerg     return &res_init.resources.null_res;
90*c303c47eSjoerg }
91*c303c47eSjoerg 
92*c303c47eSjoerg // default_memory_resource()
93*c303c47eSjoerg 
94*c303c47eSjoerg static memory_resource *
__default_memory_resource(bool set=false,memory_resource * new_res=nullptr)95*c303c47eSjoerg __default_memory_resource(bool set = false, memory_resource * new_res = nullptr) noexcept
96*c303c47eSjoerg {
97*c303c47eSjoerg #ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
98*c303c47eSjoerg     _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
99*c303c47eSjoerg         ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
100*c303c47eSjoerg     if (set) {
101*c303c47eSjoerg         new_res = new_res ? new_res : new_delete_resource();
102*c303c47eSjoerg         // TODO: Can a weaker ordering be used?
103*c303c47eSjoerg         return _VSTD::atomic_exchange_explicit(
104*c303c47eSjoerg             &__res, new_res, memory_order_acq_rel);
105*c303c47eSjoerg     }
106*c303c47eSjoerg     else {
107*c303c47eSjoerg         return _VSTD::atomic_load_explicit(
108*c303c47eSjoerg             &__res, memory_order_acquire);
109*c303c47eSjoerg     }
110*c303c47eSjoerg #elif !defined(_LIBCPP_HAS_NO_THREADS)
111*c303c47eSjoerg     _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
112*c303c47eSjoerg     static mutex res_lock;
113*c303c47eSjoerg     if (set) {
114*c303c47eSjoerg         new_res = new_res ? new_res : new_delete_resource();
115*c303c47eSjoerg         lock_guard<mutex> guard(res_lock);
116*c303c47eSjoerg         memory_resource * old_res = res;
117*c303c47eSjoerg         res = new_res;
118*c303c47eSjoerg         return old_res;
119*c303c47eSjoerg     } else {
120*c303c47eSjoerg         lock_guard<mutex> guard(res_lock);
121*c303c47eSjoerg         return res;
122*c303c47eSjoerg     }
123*c303c47eSjoerg #else
124*c303c47eSjoerg     _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
125*c303c47eSjoerg     if (set) {
126*c303c47eSjoerg         new_res = new_res ? new_res : new_delete_resource();
127*c303c47eSjoerg         memory_resource * old_res = res;
128*c303c47eSjoerg         res = new_res;
129*c303c47eSjoerg         return old_res;
130*c303c47eSjoerg     } else {
131*c303c47eSjoerg         return res;
132*c303c47eSjoerg     }
133*c303c47eSjoerg #endif
134*c303c47eSjoerg }
135*c303c47eSjoerg 
get_default_resource()136*c303c47eSjoerg memory_resource * get_default_resource() noexcept
137*c303c47eSjoerg {
138*c303c47eSjoerg     return __default_memory_resource();
139*c303c47eSjoerg }
140*c303c47eSjoerg 
set_default_resource(memory_resource * __new_res)141*c303c47eSjoerg memory_resource * set_default_resource(memory_resource * __new_res) noexcept
142*c303c47eSjoerg {
143*c303c47eSjoerg     return __default_memory_resource(true, __new_res);
144*c303c47eSjoerg }
145*c303c47eSjoerg 
146*c303c47eSjoerg _LIBCPP_END_NAMESPACE_LFTS_PMR
147