BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_heapbypassallocator.h
Go to the documentation of this file.
1/// @file bdlma_heapbypassallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_heapbypassallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_HEAPBYPASSALLOCATOR
9#define INCLUDED_BDLMA_HEAPBYPASSALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_heapbypassallocator bdlma_heapbypassallocator
15/// @brief Support memory allocation directly from virtual memory.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_heapbypassallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_heapbypassallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_heapbypassallocator-classes"> Classes </a>
26/// * <a href="#bdlma_heapbypassallocator-description"> Description </a>
27/// * <a href="#bdlma_heapbypassallocator-usage"> Usage </a>
28/// * <a href="#bdlma_heapbypassallocator-example-1-basic-usage"> Example 1: Basic Usage </a>
29///
30/// # Purpose {#bdlma_heapbypassallocator-purpose}
31/// Support memory allocation directly from virtual memory.
32///
33/// # Classes {#bdlma_heapbypassallocator-classes}
34///
35/// - bdlma::HeapBypassAllocator: memory allocator directly from virtual memory
36///
37/// @see bsls_alignmentutil
38///
39/// # Description {#bdlma_heapbypassallocator-description}
40/// The `bdlma::HeapBypassAllocator` class provided by this
41/// component implements a concrete allocator derived from the
42/// `bslma::Allocator` interface that allocates memory directly from virtual
43/// memory, bypassing the heap. Reserves virtual memory in chunks so as to grow
44/// infrequently. The chunk size can optionally be chosen by providing an
45/// argument for `replenishHint` in the constructor (see documentation for the
46/// constructor for advice on how to choose a good value for `replenishHint`).
47/// All memory allocated by this allocator is freed when the allocator's
48/// destructor is called, but not before. A natural use case is for backing
49/// large, long-lived object pools, or cases where the heap may be corrupt.
50/// @code
51/// ,---------------------------.
52/// ( bdlma::HeapBypassAllocator )
53/// `---------------------------'
54/// | ctor
55/// V
56/// ,-----------------.
57/// ( bslma::Allocator )
58/// `-----------------'
59/// dtor
60/// allocate
61/// deallocate // no-op
62/// @endcode
63///
64/// ## Usage {#bdlma_heapbypassallocator-usage}
65///
66///
67/// This section illustrates intended use of this component.
68///
69/// ### Example 1: Basic Usage {#bdlma_heapbypassallocator-example-1-basic-usage}
70///
71///
72/// Here we allocate some memory using a heap bypass allocator, then write to
73/// that memory, then read from it and verify the values written are preserved.
74/// @code
75/// {
76/// enum {
77/// k_LENGTH = 10 * 1000,
78/// k_NUM_SEGMENTS = 60
79/// };
80///
81/// bdlma::HeapBypassAllocator hbpa;
82/// @endcode
83/// First, we allocate some segments:
84/// @code
85/// char *segments[k_NUM_SEGMENTS];
86/// for (int i = 0; i < k_NUM_SEGMENTS; ++i) {
87/// segments[i] = static_cast<char *>(hbpa.allocate(k_LENGTH));
88/// BSLS_ASSERT(segments[i]);
89/// }
90/// @endcode
91/// Next, we write to the segments:
92/// @code
93/// char c = 'a';
94/// for (int i = 0; i < k_NUM_SEGMENTS; ++i) {
95/// char *segment = segments[i];
96/// for (int j = 0; j < k_LENGTH; ++j) {
97/// c = (c + 1) & 0x7f;
98/// segment[j] = c;
99/// }
100/// }
101/// @endcode
102/// Finally, we read from the segments and verify the written data is still
103/// there:
104/// @code
105/// c = 'a';
106/// for (int i = 0; i < k_NUM_SEGMENTS; ++i) {
107/// char *segment = segments[i];
108/// for (int j = 0; j < k_LENGTH; ++j) {
109/// c = (c + 1) & 0x7f;
110/// BSLS_ASSERT(segment[j] == c); (void)segment;
111/// }
112/// }
113/// @endcode
114/// Memory is released upon destruction of object `hbpa` when it goes out of
115/// scope.
116/// @code
117/// }
118/// @endcode
119/// @}
120/** @} */
121/** @} */
122
123/** @addtogroup bdl
124 * @{
125 */
126/** @addtogroup bdlma
127 * @{
128 */
129/** @addtogroup bdlma_heapbypassallocator
130 * @{
131 */
132
133#include <bdlscm_version.h>
134
135#include <bslma_allocator.h>
136#include <bslmt_mutex.h>
137#include <bsls_alignmentutil.h>
138#include <bsls_atomic.h>
139#include <bsls_keyword.h>
140#include <bsls_performancehint.h>
141#include <bsls_types.h>
142
143
144namespace bdlma {
145
146 // =========================
147 // class HeapBypassAllocator
148 // =========================
149
150/// This class allows the caller to allocate memory directly from virtual
151/// memory, without going through the heap like `malloc` or `new` would.
152/// Note that the only way to free any memory allocated with this object is
153/// to destroy the object, at which point all memory it has allocated is
154/// freed. Thread-safe.
155///
156/// See @ref bdlma_heapbypassallocator
158
159 // PRIVATE TYPES
160
161 /// Represents a chunk of memory from which allocations are subsequently
162 /// carved out. Chunks are chained in order to allow iterating over
163 /// them so they can be freed when the allocator is destroyed.
164 struct Chunk {
165
166 // PUBLIC DATA
167 bsls::AtomicUint64 d_offset; // byte offset from 'this' to free bytes
168 size_type d_size; // total size, in bytes, of this chunk
169 Chunk *d_nextChunk_p;
170 };
171
172 // DATA
173 bsls::AtomicPointer<Chunk> d_current; // current chunk (list head)
174 size_type d_chunkSize; // minimum size of new chunks
175 bslmt::Mutex d_replenishMutex; // acquired while allocating
176 Chunk d_initialChunk; // dummy chunk (at list tail)
177
178 private:
179 // NOT IMPLEMENTED
181 HeapBypassAllocator& operator=(
183
184 private:
185 // PRIVATE CLASS METHODS
186
187 /// Acquire a chunk of virtual memory of the specified `size` bytes from
188 /// the operating system. `size` must be a multiple of `d_chunkSize`
189 /// and must be greater than 0. Return the address of the allocated
190 /// chunk, or null if allocation fails. Each successful call to
191 /// `systemAllocate` must eventually be paired with a matching call to
192 /// `systemFree`.
193 static void *systemAllocate(size_type size);
194
195 /// Free the specified `chunk` of memory of the specified `size` bytes
196 /// back to the operating system. `chunk` must have been returned by a
197 /// previous call to `systemAllocate` of the same size, and not
198 /// previously freed.
199 static void systemFree(void *chunk, size_type size);
200
201 // PRIVATE MANIPULATORS
202
203 /// Initialize the linked list of chunks and round up `d_chunkSize` to
204 /// a multiple of the system's page size.
205 void init();
206
207 /// Allocate a new chunk of at least the specified `size` bytes and make
208 /// it available for subsequent calls of `allocate` to carve out memory
209 /// from. Return a pointer to the chunk on success, null otherwise.
210 Chunk *replenish(size_type size);
211
212 public:
213 // CREATORS
214
216 /// Create an empty allocator object. Optionally specify
217 /// `replenishHint` as the minimum number of bytes to allocate at a time
218 /// when the allocator's memory needs to grow. In a multi-threaded
219 /// scenario, the programmer should ensure that `replenishHint` is large
220 /// enough so that multiple threads will rarely need to replenish at the
221 /// same time in order to minimize contention.
222 explicit HeapBypassAllocator(size_type replenishHint);
223
224 /// Destroy this object, releasing all managed buffers of memory that it
225 /// has allocated.
227
228 // MANIPULATORS
229
230 /// Allocate a buffer of memory having the specified `size` (in bytes),
231 /// and alignment defined by `bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT`,
232 /// from virtual memory. If `size` is 0, return a null pointer with no
233 /// other effect. If this allocator cannot return the requested number
234 /// of bytes, then it will throw a `std::bad_alloc` exception in an
235 /// exception-enabled build, or else will abort the program in a non-
236 /// exception build. The behavior is undefined unless `0 <= size`.
237 void *allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE;
238
239 /// This method has no effect for this heap bypass allocator.
241};
242
243//=============================================================================
244// INLINE DEFINITIONS
245//=============================================================================
246
247 // -------------------------
248 // class HeapBypassAllocator
249 // -------------------------
250// MANIPULATORS
251inline
253{
255 return 0; // RETURN
256 }
258 Chunk *chunk = d_current.loadAcquire();
259 do {
260 bsls::Types::Uint64 offset = chunk->d_offset.addRelaxed(size);
261 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(offset <= chunk->d_size)) {
262 return reinterpret_cast<char *>(chunk) + (offset - size); // RETURN
263 }
264 chunk = replenish(size);
265 } while (chunk);
266 return 0;
267}
268
270{
271}
272
273} // close package namespace
274
275
276#endif
277
278// ----------------------------------------------------------------------------
279// Copyright 2016 Bloomberg Finance L.P.
280//
281// Licensed under the Apache License, Version 2.0 (the "License");
282// you may not use this file except in compliance with the License.
283// You may obtain a copy of the License at
284//
285// http://www.apache.org/licenses/LICENSE-2.0
286//
287// Unless required by applicable law or agreed to in writing, software
288// distributed under the License is distributed on an "AS IS" BASIS,
289// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
290// See the License for the specific language governing permissions and
291// limitations under the License.
292// ----------------------------- END-OF-FILE ----------------------------------
293
294/** @} */
295/** @} */
296/** @} */
Definition bdlma_heapbypassallocator.h:157
void * allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE
Definition bdlma_heapbypassallocator.h:252
void deallocate(void *) BSLS_KEYWORD_OVERRIDE
This method has no effect for this heap bypass allocator.
Definition bdlma_heapbypassallocator.h:269
HeapBypassAllocator(size_type replenishHint)
~HeapBypassAllocator() BSLS_KEYWORD_OVERRIDE
Definition bslma_allocator.h:457
std::size_t size_type
Definition bslma_allocator.h:499
Definition bslmt_mutex.h:315
Definition bsls_atomic.h:1349
TYPE * loadAcquire() const
Definition bsls_atomic.h:2395
Definition bsls_atomic.h:1195
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdlma_alignedallocator.h:276
Definition bdlt_iso8601util.h:691
static std::size_t roundUpToMaximalAlignment(std::size_t size)
Definition bsls_alignmentutil.h:452
unsigned long long Uint64
Definition bsls_types.h:137