1// <memory_resource> -*- C++ -*-
3// Copyright (C) 2018-2023 Free Software Foundation, Inc.
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
25/** @file include/memory_resource
26 * This is a Standard C++ Library header.
29#ifndef _GLIBCXX_MEMORY_RESOURCE
30#define _GLIBCXX_MEMORY_RESOURCE 1
32#pragma GCC system_header
34#include <bits/requires_hosted.h> // polymorphic allocation
36#if __cplusplus >= 201703L
38#include <bits/memory_resource.h>
39#include <vector> // vector
40#include <shared_mutex> // shared_mutex
41#include <bits/align.h> // align
42#include <debug/assertions.h>
44namespace std _GLIBCXX_VISIBILITY(default)
46_GLIBCXX_BEGIN_NAMESPACE_VERSION
49#ifdef _GLIBCXX_HAS_GTHREADS
50 // Header and all contents are present.
51# define __cpp_lib_memory_resource 201603L
53 // The pmr::synchronized_pool_resource type is missing.
54# define __cpp_lib_memory_resource 1
57#if __cplusplus >= 202002L
58# define __cpp_lib_polymorphic_allocator 201902L
59 template<typename _Tp = std::byte>
60 class polymorphic_allocator;
63 // Global memory resources
65 /// A pmr::memory_resource that uses `new` to allocate memory
66 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
68 new_delete_resource() noexcept;
70 /// A pmr::memory_resource that always throws `bad_alloc`
71 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
73 null_memory_resource() noexcept;
75 /// Replace the default memory resource pointer
76 [[__gnu__::__returns_nonnull__]]
78 set_default_resource(memory_resource* __r) noexcept;
80 /// Get the current default memory resource pointer
81 [[__gnu__::__returns_nonnull__]]
83 get_default_resource() noexcept;
85 // Pool resource classes
87#ifdef _GLIBCXX_HAS_GTHREADS
88 class synchronized_pool_resource;
90 class unsynchronized_pool_resource;
91 class monotonic_buffer_resource;
93 /// Parameters for tuning a pool resource's behaviour.
96 /** @brief Upper limit on number of blocks in a chunk.
98 * A lower value prevents allocating huge chunks that could remain mostly
99 * unused, but means pools will need to replenished more frequently.
101 size_t max_blocks_per_chunk = 0;
103 /* @brief Largest block size (in bytes) that should be served from pools.
105 * Larger allocations will be served directly by the upstream resource,
106 * not from one of the pools managed by the pool resource.
108 size_t largest_required_pool_block = 0;
111 // Common implementation details for un-/synchronized pool resources.
112 class __pool_resource
114 friend class synchronized_pool_resource;
115 friend class unsynchronized_pool_resource;
117 __pool_resource(const pool_options& __opts, memory_resource* __upstream);
121 __pool_resource(const __pool_resource&) = delete;
122 __pool_resource& operator=(const __pool_resource&) = delete;
124 // Allocate a large unpooled block.
126 allocate(size_t __bytes, size_t __alignment);
128 // Deallocate a large unpooled block.
130 deallocate(void* __p, size_t __bytes, size_t __alignment);
133 // Deallocate unpooled memory.
134 void release() noexcept;
136 memory_resource* resource() const noexcept
137 { return _M_unpooled.get_allocator().resource(); }
141 _Pool* _M_alloc_pools();
143 const pool_options _M_opts;
146 // Collection of blocks too big for any pool, sorted by address.
147 // This also stores the only copy of the upstream memory resource pointer.
148 _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
153#ifdef _GLIBCXX_HAS_GTHREADS
154 /// A thread-safe memory resource that manages pools of fixed-size blocks.
155 class synchronized_pool_resource : public memory_resource
158 synchronized_pool_resource(const pool_options& __opts,
159 memory_resource* __upstream)
160 __attribute__((__nonnull__));
162 synchronized_pool_resource()
163 : synchronized_pool_resource(pool_options(), get_default_resource())
167 synchronized_pool_resource(memory_resource* __upstream)
168 __attribute__((__nonnull__))
169 : synchronized_pool_resource(pool_options(), __upstream)
173 synchronized_pool_resource(const pool_options& __opts)
174 : synchronized_pool_resource(__opts, get_default_resource()) { }
176 synchronized_pool_resource(const synchronized_pool_resource&) = delete;
178 virtual ~synchronized_pool_resource();
180 synchronized_pool_resource&
181 operator=(const synchronized_pool_resource&) = delete;
186 upstream_resource() const noexcept
187 __attribute__((__returns_nonnull__))
188 { return _M_impl.resource(); }
190 pool_options options() const noexcept { return _M_impl._M_opts; }
194 do_allocate(size_t __bytes, size_t __alignment) override;
197 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
200 do_is_equal(const memory_resource& __other) const noexcept override
201 { return this == &__other; }
204 // Thread-specific pools (only public for access by implementation details)
208 _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
209 _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
210 auto _M_thread_specific_pools() noexcept;
212 __pool_resource _M_impl;
213 __gthread_key_t _M_key;
214 // Linked list of thread-specific pools. All threads share _M_tpools[0].
215 _TPools* _M_tpools = nullptr;
216 mutable shared_mutex _M_mx;
220 /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
221 class unsynchronized_pool_resource : public memory_resource
224 [[__gnu__::__nonnull__]]
225 unsynchronized_pool_resource(const pool_options& __opts,
226 memory_resource* __upstream);
228 unsynchronized_pool_resource()
229 : unsynchronized_pool_resource(pool_options(), get_default_resource())
232 [[__gnu__::__nonnull__]]
234 unsynchronized_pool_resource(memory_resource* __upstream)
235 : unsynchronized_pool_resource(pool_options(), __upstream)
239 unsynchronized_pool_resource(const pool_options& __opts)
240 : unsynchronized_pool_resource(__opts, get_default_resource()) { }
242 unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
244 virtual ~unsynchronized_pool_resource();
246 unsynchronized_pool_resource&
247 operator=(const unsynchronized_pool_resource&) = delete;
251 [[__gnu__::__returns_nonnull__]]
253 upstream_resource() const noexcept
254 { return _M_impl.resource(); }
256 pool_options options() const noexcept { return _M_impl._M_opts; }
260 do_allocate(size_t __bytes, size_t __alignment) override;
263 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
266 do_is_equal(const memory_resource& __other) const noexcept override
267 { return this == &__other; }
270 using _Pool = __pool_resource::_Pool;
272 auto _M_find_pool(size_t) noexcept;
274 __pool_resource _M_impl;
275 _Pool* _M_pools = nullptr;
278 class monotonic_buffer_resource : public memory_resource
282 monotonic_buffer_resource(memory_resource* __upstream) noexcept
283 __attribute__((__nonnull__))
284 : _M_upstream(__upstream)
285 { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
287 monotonic_buffer_resource(size_t __initial_size,
288 memory_resource* __upstream) noexcept
289 __attribute__((__nonnull__))
290 : _M_next_bufsiz(__initial_size),
291 _M_upstream(__upstream)
293 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
294 _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
297 monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
298 memory_resource* __upstream) noexcept
299 __attribute__((__nonnull__(4)))
300 : _M_current_buf(__buffer), _M_avail(__buffer_size),
301 _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
302 _M_upstream(__upstream),
303 _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
305 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
306 _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
309 monotonic_buffer_resource() noexcept
310 : monotonic_buffer_resource(get_default_resource())
314 monotonic_buffer_resource(size_t __initial_size) noexcept
315 : monotonic_buffer_resource(__initial_size, get_default_resource())
318 monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
319 : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
322 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
324 virtual ~monotonic_buffer_resource(); // key function
326 monotonic_buffer_resource&
327 operator=(const monotonic_buffer_resource&) = delete;
333 _M_release_buffers();
335 // reset to initial state at contruction:
336 if ((_M_current_buf = _M_orig_buf))
338 _M_avail = _M_orig_size;
339 _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
344 _M_next_bufsiz = _M_orig_size;
349 upstream_resource() const noexcept
350 __attribute__((__returns_nonnull__))
351 { return _M_upstream; }
355 do_allocate(size_t __bytes, size_t __alignment) override
357 if (__builtin_expect(__bytes == 0, false))
358 __bytes = 1; // Ensures we don't return the same pointer twice.
360 void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
361 if (__builtin_expect(__p == nullptr, false))
363 _M_new_buffer(__bytes, __alignment);
364 __p = _M_current_buf;
366 _M_current_buf = (char*)_M_current_buf + __bytes;
372 do_deallocate(void*, size_t, size_t) override
376 do_is_equal(const memory_resource& __other) const noexcept override
377 { return this == &__other; }
380 // Update _M_current_buf and _M_avail to refer to a new buffer with
381 // at least the specified size and alignment, allocated from upstream.
383 _M_new_buffer(size_t __bytes, size_t __alignment);
385 // Deallocate all buffers obtained from upstream.
387 _M_release_buffers() noexcept;
390 _S_next_bufsize(size_t __buffer_size) noexcept
392 if (__builtin_expect(__buffer_size == 0, false))
394 return __buffer_size * _S_growth_factor;
397 static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
398 static constexpr float _S_growth_factor = 1.5;
400 void* _M_current_buf = nullptr;
402 size_t _M_next_bufsiz = _S_init_bufsize;
404 // Initial values set at construction and reused by release():
405 memory_resource* const _M_upstream;
406 void* const _M_orig_buf = nullptr;
407 size_t const _M_orig_size = _M_next_bufsiz;
410 _Chunk* _M_head = nullptr;
414_GLIBCXX_END_NAMESPACE_VERSION
418#endif // _GLIBCXX_MEMORY_RESOURCE