Stxxl  1.3.2
aligned_alloc.h
1 /***************************************************************************
2  * include/stxxl/bits/common/aligned_alloc.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2002 Roman Dementiev <[email protected]>
7  * Copyright (C) 2009 Andreas Beckmann <[email protected]>
8  *
9  * Distributed under the Boost Software License, Version 1.0.
10  * (See accompanying file LICENSE_1_0.txt or copy at
11  * http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #ifndef STXXL_ALIGNED_ALLOC
15 #define STXXL_ALIGNED_ALLOC
16 
17 #include <cstdlib>
18 #include <cassert>
19 #include <stxxl/bits/verbose.h>
20 #include <stxxl/bits/common/utils.h>
21 
22 
23 #ifndef STXXL_VERBOSE_ALIGNED_ALLOC
24 #define STXXL_VERBOSE_ALIGNED_ALLOC STXXL_VERBOSE2
25 #endif
26 
27 __STXXL_BEGIN_NAMESPACE
28 
29 template <typename must_be_int>
30 struct aligned_alloc_settings {
31  static bool may_use_realloc;
32 };
33 
34 template <typename must_be_int>
35 bool aligned_alloc_settings<must_be_int>::may_use_realloc = true;
36 
37 // meta_info_size > 0 is needed for array allocations that have overhead
38 //
39 // meta_info
40 // aligned begin of data unallocated behind data
41 // v v v
42 // ----===============#MMMM========================------
43 // ^ ^^ ^
44 // buffer result result+m_i_size+size
45 // pointer to buffer
46 // (---) unallocated, (===) allocated memory
47 
48 template <size_t ALIGNMENT>
49 inline void * aligned_alloc(size_t size, size_t meta_info_size = 0)
50 {
51  STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">(), size = " << size << ", meta info size = " << meta_info_size);
52 #if !defined(STXXL_WASTE_MORE_MEMORY_FOR_IMPROVED_ACCESS_AFTER_ALLOCATED_MEMORY_CHECKS)
53  // malloc()/realloc() variant that frees the unused amount of memory
54  // after the data area of size 'size'. realloc() from valgrind does not
55  // preserve the old memory area when shrinking, so out-of-bounds
56  // accesses can't be detected easily.
57  // Overhead: about ALIGNMENT bytes.
58  size_t alloc_size = ALIGNMENT + sizeof(char *) + meta_info_size + size;
59  char * buffer = (char *)std::malloc(alloc_size);
60 #else
61  // More space consuming and memory fragmenting variant using
62  // posix_memalign() instead of malloc()/realloc(). Ensures that the end
63  // of the data area (of size 'size') will match the end of the allocated
64  // block, so no corrections are neccessary and
65  // access-behind-allocated-memory problems can be easily detected by
66  // valgrind. Usually produces an extra memory fragment of about
67  // ALIGNMENT bytes.
68  // Overhead: about 2 * ALIGNMENT bytes.
69  size_t alloc_size = ALIGNMENT * div_ceil(sizeof(char *) + meta_info_size, ALIGNMENT) + size;
70  char * buffer;
71  if (posix_memalign((void **)&buffer, ALIGNMENT, alloc_size) != 0)
72  throw std::bad_alloc();
73 #endif
74  if (buffer == NULL)
75  throw std::bad_alloc();
76  #ifdef STXXL_ALIGNED_CALLOC
77  memset(buffer, 0, alloc_size);
78  #endif
79  char * reserve_buffer = buffer + sizeof(char *) + meta_info_size;
80  char * result = reserve_buffer + ALIGNMENT -
81  (((unsigned long)reserve_buffer) % (ALIGNMENT)) - meta_info_size;
82  STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">() address " << (void *)result << " lost " << (result - buffer) << " bytes");
83  assert(long(result - buffer) >= long(sizeof(char *)));
84 
85  // free unused memory behind the data area
86  // so access behind the requested size can be recognized
87  size_t realloc_size = (result - buffer) + meta_info_size + size;
88  if (realloc_size < alloc_size && aligned_alloc_settings<int>::may_use_realloc) {
89  char * realloced = (char *)std::realloc(buffer, realloc_size);
90  if (buffer != realloced) {
91  // hmm, realloc does move the memory block around while shrinking,
92  // might run under valgrind, so disable realloc and retry
93  STXXL_ERRMSG("stxxl::aligned_alloc: disabling realloc()");
94  std::free(realloced);
95  aligned_alloc_settings<int>::may_use_realloc = false;
96  return aligned_alloc<ALIGNMENT>(size, meta_info_size);
97  }
98  assert(result + size <= buffer + realloc_size);
99  }
100 
101  *(((char **)result) - 1) = buffer;
102  STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">(), allocated at " << (void *)buffer << " returning " << (void *)result);
103  STXXL_VERBOSE_ALIGNED_ALLOC("stxxl::aligned_alloc<" << ALIGNMENT <<
104  ">(size = " << size << ", meta info size = " << meta_info_size <<
105  ") => buffer = " << (void *)buffer << ", ptr = " << (void *)result);
106 
107  return result;
108 }
109 
110 template <size_t ALIGNMENT>
111 inline void
112 aligned_dealloc(void * ptr)
113 {
114  if (!ptr)
115  return;
116  char * buffer = *(((char **)ptr) - 1);
117  STXXL_VERBOSE_ALIGNED_ALLOC("stxxl::aligned_dealloc<" << ALIGNMENT << ">(), ptr = " << ptr << ", buffer = " << (void *)buffer);
118  std::free(buffer);
119 }
120 
121 __STXXL_END_NAMESPACE
122 
123 #endif // !STXXL_ALIGNED_ALLOC
124 // vim: et:ts=4:sw=4