BDE 4.39.x 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///
153/// \note Note that the only way to free any memory allocated with this object is
154/// to destroy the object, at which point all memory it has allocated is
155/// freed. Thread-safe.
156///
157/// See @ref bdlma_heapbypassallocator
159
160 // PRIVATE TYPES
161
162 /// Represents a chunk of memory from which allocations are subsequently
163 /// carved out. Chunks are chained in order to allow iterating over
164 /// them so they can be freed when the allocator is destroyed.
165 ///
166 /// See @ref bdlma_heapbypassallocator
167 struct Chunk {
168
169 // PUBLIC DATA
170 bsls::AtomicUint64 d_offset; // byte offset from `this` to free bytes
171 size_type d_size; // total size, in bytes, of this chunk
172 Chunk *d_nextChunk_p;
173 };
174
175 // DATA
176 bsls::AtomicPointer<Chunk> d_current; // current chunk (list head)
177 size_type d_chunkSize; // minimum size of new chunks
178 bslmt::Mutex d_replenishMutex; // acquired while allocating
179 Chunk d_initialChunk; // dummy chunk (at list tail)
180
181 private:
182 // NOT IMPLEMENTED
184 HeapBypassAllocator& operator=(
186
187 private:
188 // PRIVATE CLASS METHODS
189
190 /// Acquire a chunk of virtual memory of the specified `size` bytes from
191 /// the operating system. `size` must be a multiple of `d_chunkSize`
192 /// and must be greater than 0. Return the address of the allocated
193 /// chunk, or null if allocation fails. Each successful call to
194 /// `systemAllocate` must eventually be paired with a matching call to
195 /// `systemFree`.
196 static void *systemAllocate(size_type size);
197
198 /// Free the specified `chunk` of memory of the specified `size` bytes
199 /// back to the operating system. `chunk` must have been returned by a
200 /// previous call to `systemAllocate` of the same size, and not
201 /// previously freed.
202 static void systemFree(void *chunk, size_type size);
203
204 // PRIVATE MANIPULATORS
205
206 /// Initialize the linked list of chunks and round up `d_chunkSize` to
207 /// a multiple of the system's page size.
208 void init();
209
210 /// Allocate a new chunk of at least the specified `size` bytes and make
211 /// it available for subsequent calls of `allocate` to carve out memory
212 /// from. Return a pointer to the chunk on success, null otherwise.
213 Chunk *replenish(size_type size);
214
215 public:
216 // CREATORS
217
218 /// Create an empty allocator object. Optionally specify
219 /// `replenishHint` as the minimum number of bytes to allocate at a time
220 /// when the allocator's memory needs to grow. In a multi-threaded
221 /// scenario, the programmer should ensure that `replenishHint` is large
222 /// enough so that multiple threads will rarely need to replenish at the
223 /// same time in order to minimize contention.
225 explicit HeapBypassAllocator(size_type replenishHint);
226
227 /// Destroy this object, releasing all managed buffers of memory that it
228 /// has allocated.
230
231 // MANIPULATORS
232
233 /// Allocate a buffer of memory having the specified `size` (in bytes),
234 /// and alignment defined by `bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT`,
235 /// from virtual memory. If `size` is 0, return a null pointer with no
236 /// other effect. If this allocator cannot return the requested number
237 /// of bytes, then it will throw a `std::bad_alloc` exception in an
238 /// exception-enabled build, or else will abort the program in a non- exception build.
239 ///
240 /// \pre The behavior is undefined unless `0 <= size`.
241 void *allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE;
242
243 /// This method has no effect for this heap bypass allocator.
245};
246
247//=============================================================================
248// INLINE DEFINITIONS
249//=============================================================================
250
251 // -------------------------
252 // class HeapBypassAllocator
253 // -------------------------
254// MANIPULATORS
255inline
257{
259 return 0; // RETURN
260 }
262 Chunk *chunk = d_current.loadAcquire();
263 do {
264 bsls::Types::Uint64 offset = chunk->d_offset.addRelaxed(size);
265 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(offset <= chunk->d_size)) {
266 return reinterpret_cast<char *>(chunk) + (offset - size); // RETURN
267 }
268 chunk = replenish(size);
269 } while (chunk);
270 return 0;
271}
272
274{
275}
276
277} // close package namespace
278
279
280#endif
281
282// ----------------------------------------------------------------------------
283// Copyright 2016 Bloomberg Finance L.P.
284//
285// Licensed under the Apache License, Version 2.0 (the "License");
286// you may not use this file except in compliance with the License.
287// You may obtain a copy of the License at
288//
289// http://www.apache.org/licenses/LICENSE-2.0
290//
291// Unless required by applicable law or agreed to in writing, software
292// distributed under the License is distributed on an "AS IS" BASIS,
293// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
294// See the License for the specific language governing permissions and
295// limitations under the License.
296// ----------------------------- END-OF-FILE ----------------------------------
297
298/** @} */
299/** @} */
300/** @} */
Definition bdlma_heapbypassallocator.h:158
void * allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE
Definition bdlma_heapbypassallocator.h:256
void deallocate(void *) BSLS_KEYWORD_OVERRIDE
This method has no effect for this heap bypass allocator.
Definition bdlma_heapbypassallocator.h:273
HeapBypassAllocator(size_type replenishHint)
~HeapBypassAllocator() BSLS_KEYWORD_OVERRIDE
Definition bslma_allocator.h:545
std::size_t size_type
Definition bslma_allocator.h:593
Definition bslmt_mutex.h:317
Definition bsls_atomic.h:1362
TYPE * loadAcquire() const
Definition bsls_atomic.h:2416
Definition bsls_atomic.h:1205
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
#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:278
Definition bdlt_iso8601util.h:707
static std::size_t roundUpToMaximalAlignment(std::size_t size)
Definition bsls_alignmentutil.h:522
unsigned long long Uint64
Definition bsls_types.h:139