this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.org>
5 *
6 * Copyright:
7 * Christian Schulte, 2008
8 *
9 * This file is part of Gecode, the generic constraint
10 * development environment:
11 * http://www.gecode.org
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34#include <cstddef>
35
36namespace Gecode {
37
38 /**
39 * \defgroup FuncMemRegion Region memory management
40 *
41 * A region provides a handle to temporary memory owned by
42 * a space. The memory will be managed in a stack fashion, that is,
43 * the memory allocated through a region will be released
44 * only after the region is deleted and all other regions
45 * created later also have been deleted.
46 *
47 * In case a memory request cannot be fulfilled from a space's region,
48 * heap memory is allocated and returned to the operating system
49 * as soon as the region is deleted.
50 *
51 * \ingroup FuncMem
52 */
53 //@{
54 /// Handle to region
55 class Region {
56 private:
57 /// Heap chunks used for regions
58 class Chunk : public HeapAllocated {
59 public:
60 /// Amount of free memory
61 size_t free;
62 /// The actual memory area (allocated from top to bottom)
63 alignas((alignof(std::max_align_t) > GECODE_MEMORY_ALIGNMENT) ?
64 alignof(std::max_align_t) : GECODE_MEMORY_ALIGNMENT)
65 double area[Kernel::MemoryConfig::region_area_size / sizeof(double)];
66 /// A pointer to another chunk
67 Chunk* next;
68 /// Return memory if available
69 bool alloc(size_t s, void*& p);
70 /// Free allocated memory (reset chunk)
71 void reset(void);
72 };
73 /// The heap chunk in use
74 Chunk* chunk;
75 /// A pool of heap chunks to be used for regions
76 class GECODE_KERNEL_EXPORT Pool {
77 protected:
78 /// The current chunk
79 Chunk* c;
80 /// Number of cached chunks
81 unsigned int n_c;
82 /// Mutex to synchronize globally shared access
83 Support::Mutex m;
84 public:
85 /// Initialize pool
86 Pool(void);
87 /// Get a new chunk
88 Chunk* chunk(void);
89 /// Return chunk and possible free unused chunk \a u
90 void chunk(Chunk* u);
91 /// Delete pool
92 ~Pool(void);
93 };
94 /// Just use a single static pool for heap chunks
95 GECODE_KERNEL_EXPORT static Pool& pool();
96 /// Heap information data structure
97 class HeapInfo {
98 public:
99 /// Number of allocated heap blocks
100 unsigned int n;
101 /// Limit of allocated heap blocks
102 unsigned int size;
103 /// Pointers to allocated heap blocks (more entries)
104 void* blocks[1];
105 };
106 /**
107 * \brief Heap allocation information
108 *
109 * If nullptr, no heap memory has been allocated. If the pointer
110 * is marked, it points to a single heap allocated block. Otherwise,
111 * it points to a HeapInfo data structure.
112 */
113 void* hi;
114 /// Allocate memory from heap
115 GECODE_KERNEL_EXPORT void* heap_alloc(size_t s);
116 /// Free memory previously allocated from heap
117 GECODE_KERNEL_EXPORT void heap_free(void);
118 public:
119 /// Initialize region
120 Region(void);
121 /**
122 * \brief Free allocate memory
123 *
124 * Note that in fact not all memory is freed, memory that has been
125 * allocated for large allocation requests will not be freed.
126 */
127 void free(void);
128 /// \name Typed allocation routines
129 //@{
130 /**
131 * \brief Allocate block of \a n objects of type \a T from region
132 *
133 * Note that this function implements C++ semantics: the default
134 * constructor of \a T is run for all \a n objects.
135 */
136 template<class T>
137 T* alloc(long unsigned int n);
138 /**
139 * \brief Allocate block of \a n objects of type \a T from region
140 *
141 * Note that this function implements C++ semantics: the default
142 * constructor of \a T is run for all \a n objects.
143 */
144 template<class T>
145 T* alloc(long int n);
146 /**
147 * \brief Allocate block of \a n objects of type \a T from region
148 *
149 * Note that this function implements C++ semantics: the default
150 * constructor of \a T is run for all \a n objects.
151 */
152 template<class T>
153 T* alloc(unsigned int n);
154 /**
155 * \brief Allocate block of \a n objects of type \a T from region
156 *
157 * Note that this function implements C++ semantics: the default
158 * constructor of \a T is run for all \a n objects.
159 */
160 template<class T>
161 T* alloc(int n);
162 /**
163 * \brief Delete \a n objects allocated from the region starting at \a b
164 *
165 * Note that this function implements C++ semantics: the destructor
166 * of \a T is run for all \a n objects.
167 *
168 * Note that the memory is not freed, the only effect is running the
169 * destructors.
170 */
171 template<class T>
172 void free(T* b, long unsigned int n);
173 /**
174 * \brief Delete \a n objects allocated from the region starting at \a b
175 *
176 * Note that this function implements C++ semantics: the destructor
177 * of \a T is run for all \a n objects.
178 *
179 * Note that the memory is not freed, the only effect is running the
180 * destructors.
181 */
182 template<class T>
183 void free(T* b, long int n);
184 /**
185 * \brief Delete \a n objects allocated from the region starting at \a b
186 *
187 * Note that this function implements C++ semantics: the destructor
188 * of \a T is run for all \a n objects.
189 *
190 * Note that the memory is not freed, the only effect is running the
191 * destructors.
192 */
193 template<class T>
194 void free(T* b, unsigned int n);
195 /**
196 * \brief Delete \a n objects allocated from the region starting at \a b
197 *
198 * Note that this function implements C++ semantics: the destructor
199 * of \a T is run for all \a n objects.
200 *
201 * Note that the memory is not freed, the only effect is running the
202 * destructors.
203 */
204 template<class T>
205 void free(T* b, int n);
206 /**
207 * \brief Reallocate block of \a n objects starting at \a b to \a m objects of type \a T from the region
208 *
209 * Note that this function implements C++ semantics: the copy constructor
210 * of \a T is run for all \f$\min(n,m)\f$ objects, the default
211 * constructor of \a T is run for all remaining
212 * \f$\max(n,m)-\min(n,m)\f$ objects, and the destrucor of \a T is
213 * run for all \a n objects in \a b.
214 *
215 * Returns the address of the new block.
216 */
217 template<class T>
218 T* realloc(T* b, long unsigned int n, long unsigned int m);
219 /**
220 * \brief Reallocate block of \a n objects starting at \a b to \a m objects of type \a T from the region
221 *
222 * Note that this function implements C++ semantics: the copy constructor
223 * of \a T is run for all \f$\min(n,m)\f$ objects, the default
224 * constructor of \a T is run for all remaining
225 * \f$\max(n,m)-\min(n,m)\f$ objects, and the destrucor of \a T is
226 * run for all \a n objects in \a b.
227 *
228 * Returns the address of the new block.
229 */
230 template<class T>
231 T* realloc(T* b, long int n, long int m);
232 /**
233 * \brief Reallocate block of \a n objects starting at \a b to \a m objects of type \a T from the region
234 *
235 * Note that this function implements C++ semantics: the copy constructor
236 * of \a T is run for all \f$\min(n,m)\f$ objects, the default
237 * constructor of \a T is run for all remaining
238 * \f$\max(n,m)-\min(n,m)\f$ objects, and the destrucor of \a T is
239 * run for all \a n objects in \a b.
240 *
241 * Returns the address of the new block.
242 */
243 template<class T>
244 T* realloc(T* b, unsigned int n, unsigned int m);
245 /**
246 * \brief Reallocate block of \a n objects starting at \a b to \a m objects of type \a T from the region
247 *
248 * Note that this function implements C++ semantics: the copy constructor
249 * of \a T is run for all \f$\min(n,m)\f$ objects, the default
250 * constructor of \a T is run for all remaining
251 * \f$\max(n,m)-\min(n,m)\f$ objects, and the destrucor of \a T is
252 * run for all \a n objects in \a b.
253 *
254 * Returns the address of the new block.
255 */
256 template<class T>
257 T* realloc(T* b, int n, int m);
258 //@}
259 /// \name Raw allocation routines
260 //@{
261 /// Allocate memory from region
262 void* ralloc(size_t s);
263 /**
264 * \brief Free memory previously allocated
265 *
266 * Note that the memory is only guaranteed to be freed after the
267 * region object itself gets deleted.
268 */
269 void rfree(void* p, size_t s);
270 //@}
271 /// \name Construction routines
272 //@{
273 /**
274 * \brief Constructs a single object of type \a T from region using the default constructor.
275 */
276 template<class T>
277 T& construct(void);
278 /**
279 * \brief Constructs a single object of type \a T from region using a unary constructor.
280 *
281 * The parameter is passed as a const reference.
282 */
283 template<class T, typename A1>
284 T& construct(A1 const& a1);
285 /**
286 * \brief Constructs a single object of type \a T from region using a binary constructor.
287 *
288 * The parameters are passed as const references.
289 */
290 template<class T, typename A1, typename A2>
291 T& construct(A1 const& a1, A2 const& a2);
292 /**
293 * \brief Constructs a single object of type \a T from region using a ternary constructor.
294 *
295 * The parameters are passed as const references.
296 */
297 template<class T, typename A1, typename A2, typename A3>
298 T& construct(A1 const& a1, A2 const& a2, A3 const& a3);
299 /**
300 * \brief Constructs a single object of type \a T from region using a quaternary constructor.
301 *
302 * The parameters are passed as const references.
303 */
304 template<class T, typename A1, typename A2, typename A3, typename A4>
305 T& construct(A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4);
306 /**
307 * \brief Constructs a single object of type \a T from region using a quinary constructor.
308 *
309 * The parameters are passed as const references.
310 */
311 template<class T, typename A1, typename A2, typename A3, typename A4, typename A5>
312 T& construct(A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4, A5 const& a5);
313 //@}
314 /// Return memory
315 ~Region(void);
316
317 /// Allocate memory from heap (disabled)
318 static void* operator new(size_t s) = delete;
319 /// Free memory allocated from heap (disabled)
320 static void operator delete(void* p) = delete;
321 /// Copy constructor (disabled)
322 Region(const Region&) = delete;
323 /// Assignment operator (disabled)
324 const Region& operator =(const Region&) = delete;
325 };
326 //@}
327
328
329 /*
330 * Implementation
331 *
332 */
333 forceinline bool
334 Region::Chunk::alloc(size_t s, void*& p) {
335 Kernel::MemoryConfig::align
336 (s,((alignof(std::max_align_t) > GECODE_MEMORY_ALIGNMENT) ?
337 alignof(std::max_align_t) : GECODE_MEMORY_ALIGNMENT));
338 if (s > free)
339 return false;
340 free -= s;
341 p = ptr_cast<char*>(&area[0]) + free;
342 return true;
343 }
344
345 forceinline void
346 Region::Chunk::reset(void) {
347 free = Kernel::MemoryConfig::region_area_size;
348 }
349
350
351 forceinline
352 Region::Region(void)
353 : chunk(pool().chunk()), hi(nullptr) {}
354
355 forceinline void
356 Region::free(void) {
357 chunk->reset();
358 }
359
360 forceinline void*
361 Region::ralloc(size_t s) {
362 void* p;
363 if (chunk->alloc(s,p))
364 return p;
365 else
366 return heap_alloc(s);
367 }
368
369 forceinline void
370 Region::rfree(void*, size_t) {}
371
372 forceinline
373 Region::~Region(void) {
374 pool().chunk(chunk);
375 if (hi != nullptr)
376 heap_free();
377 }
378
379
380 /*
381 * Typed allocation routines
382 *
383 */
384 template<class T>
385 forceinline T*
386 Region::alloc(long unsigned int n) {
387 T* p = static_cast<T*>(ralloc(sizeof(T)*n));
388 for (long unsigned int i=0U; i<n; i++)
389 (void) new (p+i) T();
390 return p;
391 }
392 template<class T>
393 forceinline T*
394 Region::alloc(long int n) {
395 assert(n >= 0);
396 return alloc<T>(static_cast<long unsigned int>(n));
397 }
398 template<class T>
399 forceinline T*
400 Region::alloc(unsigned int n) {
401 return alloc<T>(static_cast<long unsigned int>(n));
402 }
403 template<class T>
404 forceinline T*
405 Region::alloc(int n) {
406 assert(n >= 0);
407 return alloc<T>(static_cast<long unsigned int>(n));
408 }
409
410 template<class T>
411 forceinline void
412 Region::free(T* b, long unsigned int n) {
413 for (long unsigned int i=0U; i<n; i++)
414 b[i].~T();
415 rfree(b,n*sizeof(T));
416 }
417 template<class T>
418 forceinline void
419 Region::free(T* b, long int n) {
420 assert(n >= 0);
421 free<T>(b,static_cast<long unsigned int>(n));
422 }
423 template<class T>
424 forceinline void
425 Region::free(T* b, unsigned int n) {
426 free<T>(b,static_cast<long unsigned int>(n));
427 }
428 template<class T>
429 forceinline void
430 Region::free(T* b, int n) {
431 assert(n >= 0);
432 free<T>(b,static_cast<long unsigned int>(n));
433 }
434
435 template<class T>
436 forceinline T*
437 Region::realloc(T* b, long unsigned int n, long unsigned int m) {
438 if (n < m) {
439 T* p = static_cast<T*>(ralloc(sizeof(T)*m));
440 for (long unsigned int i=0U; i<n; i++)
441 (void) new (p+i) T(b[i]);
442 for (long unsigned int i=n; i<m; i++)
443 (void) new (p+i) T();
444 free<T>(b,n);
445 return p;
446 } else {
447 free<T>(b+m,m-n);
448 return b;
449 }
450 }
451 template<class T>
452 forceinline T*
453 Region::realloc(T* b, long int n, long int m) {
454 assert((n >= 0) && (m >= 0));
455 return realloc<T>(b,static_cast<long unsigned int>(n),
456 static_cast<long unsigned int>(m));
457 }
458 template<class T>
459 forceinline T*
460 Region::realloc(T* b, unsigned int n, unsigned int m) {
461 return realloc<T>(b,static_cast<long unsigned int>(n),
462 static_cast<long unsigned int>(m));
463 }
464 template<class T>
465 forceinline T*
466 Region::realloc(T* b, int n, int m) {
467 assert((n >= 0) && (m >= 0));
468 return realloc<T>(b,static_cast<long unsigned int>(n),
469 static_cast<long unsigned int>(m));
470 }
471
472 /*
473 * Region construction support
474 *
475 */
476 template<class T>
477 forceinline T&
478 Region::construct(void) {
479 return alloc<T>(1);
480 }
481 template<class T, typename A1>
482 forceinline T&
483 Region::construct(A1 const& a1) {
484 T& t = *static_cast<T*>(ralloc(sizeof(T)));
485 new (&t) T(a1);
486 return t;
487 }
488 template<class T, typename A1, typename A2>
489 forceinline T&
490 Region::construct(A1 const& a1, A2 const& a2) {
491 T& t = *static_cast<T*>(ralloc(sizeof(T)));
492 new (&t) T(a1,a2);
493 return t;
494 }
495 template<class T, typename A1, typename A2, typename A3>
496 forceinline T&
497 Region::construct(A1 const& a1, A2 const& a2, A3 const& a3) {
498 T& t = *static_cast<T*>(ralloc(sizeof(T)));
499 new (&t) T(a1,a2,a3);
500 return t;
501 }
502 template<class T, typename A1, typename A2, typename A3, typename A4>
503 forceinline T&
504 Region::construct(A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4) {
505 T& t = *static_cast<T*>(ralloc(sizeof(T)));
506 new (&t) T(a1,a2,a3,a4);
507 return t;
508 }
509 template<class T, typename A1, typename A2, typename A3, typename A4, typename A5>
510 forceinline T&
511 Region::construct(A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4, A5 const& a5) {
512 T& t = *static_cast<T*>(ralloc(sizeof(T)));
513 new (&t) T(a1,a2,a3,a4,a5);
514 return t;
515 }
516
517}
518
519// STATISTICS: kernel-memory