Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/common/aligned_alloc.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de> 00007 * Copyright (C) 2009 Andreas Beckmann <beckmann@cs.uni-frankfurt.de> 00008 * 00009 * Distributed under the Boost Software License, Version 1.0. 00010 * (See accompanying file LICENSE_1_0.txt or copy at 00011 * http://www.boost.org/LICENSE_1_0.txt) 00012 **************************************************************************/ 00013 00014 #ifndef STXXL_ALIGNED_ALLOC 00015 #define STXXL_ALIGNED_ALLOC 00016 00017 #include <cstdlib> 00018 #include <cassert> 00019 #include <stxxl/bits/verbose.h> 00020 #include <stxxl/bits/common/utils.h> 00021 00022 00023 #ifndef STXXL_VERBOSE_ALIGNED_ALLOC 00024 #define STXXL_VERBOSE_ALIGNED_ALLOC STXXL_VERBOSE2 00025 #endif 00026 00027 __STXXL_BEGIN_NAMESPACE 00028 00029 template <typename must_be_int> 00030 struct aligned_alloc_settings { 00031 static bool may_use_realloc; 00032 }; 00033 00034 template <typename must_be_int> 00035 bool aligned_alloc_settings<must_be_int>::may_use_realloc = true; 00036 00037 // meta_info_size > 0 is needed for array allocations that have overhead 00038 // 00039 // meta_info 00040 // aligned begin of data unallocated behind data 00041 // v v v 00042 // ----===============#MMMM========================------ 00043 // ^ ^^ ^ 00044 // buffer result result+m_i_size+size 00045 // pointer to buffer 00046 // (---) unallocated, (===) allocated memory 00047 00048 template <size_t ALIGNMENT> 00049 inline void * aligned_alloc(size_t size, size_t meta_info_size = 0) 00050 { 00051 STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">(), size = " << size << ", meta info size = " << meta_info_size); 00052 #if !defined(STXXL_WASTE_MORE_MEMORY_FOR_IMPROVED_ACCESS_AFTER_ALLOCATED_MEMORY_CHECKS) 00053 // malloc()/realloc() variant that frees the unused amount of memory 00054 // after the data area of size 'size'. realloc() from valgrind does not 00055 // preserve the old memory area when shrinking, so out-of-bounds 00056 // accesses can't be detected easily. 00057 // Overhead: about ALIGNMENT bytes. 00058 size_t alloc_size = ALIGNMENT + sizeof(char *) + meta_info_size + size; 00059 char * buffer = (char *)std::malloc(alloc_size); 00060 #else 00061 // More space consuming and memory fragmenting variant using 00062 // posix_memalign() instead of malloc()/realloc(). Ensures that the end 00063 // of the data area (of size 'size') will match the end of the allocated 00064 // block, so no corrections are neccessary and 00065 // access-behind-allocated-memory problems can be easily detected by 00066 // valgrind. Usually produces an extra memory fragment of about 00067 // ALIGNMENT bytes. 00068 // Overhead: about 2 * ALIGNMENT bytes. 00069 size_t alloc_size = ALIGNMENT * div_ceil(sizeof(char *) + meta_info_size, ALIGNMENT) + size; 00070 char * buffer; 00071 if (posix_memalign((void **)&buffer, ALIGNMENT, alloc_size) != 0) 00072 throw std::bad_alloc(); 00073 #endif 00074 if (buffer == NULL) 00075 throw std::bad_alloc(); 00076 #ifdef STXXL_ALIGNED_CALLOC 00077 memset(buffer, 0, alloc_size); 00078 #endif 00079 char * reserve_buffer = buffer + sizeof(char *) + meta_info_size; 00080 char * result = reserve_buffer + ALIGNMENT - 00081 (((unsigned long)reserve_buffer) % (ALIGNMENT)) - meta_info_size; 00082 STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">() address " << (void *)result << " lost " << (result - buffer) << " bytes"); 00083 assert(long(result - buffer) >= long(sizeof(char *))); 00084 00085 // free unused memory behind the data area 00086 // so access behind the requested size can be recognized 00087 size_t realloc_size = (result - buffer) + meta_info_size + size; 00088 if (realloc_size < alloc_size && aligned_alloc_settings<int>::may_use_realloc) { 00089 char * realloced = (char *)std::realloc(buffer, realloc_size); 00090 if (buffer != realloced) { 00091 // hmm, realloc does move the memory block around while shrinking, 00092 // might run under valgrind, so disable realloc and retry 00093 STXXL_ERRMSG("stxxl::aligned_alloc: disabling realloc()"); 00094 std::free(realloced); 00095 aligned_alloc_settings<int>::may_use_realloc = false; 00096 return aligned_alloc<ALIGNMENT>(size, meta_info_size); 00097 } 00098 assert(result + size <= buffer + realloc_size); 00099 } 00100 00101 *(((char **)result) - 1) = buffer; 00102 STXXL_VERBOSE2("stxxl::aligned_alloc<" << ALIGNMENT << ">(), allocated at " << (void *)buffer << " returning " << (void *)result); 00103 STXXL_VERBOSE_ALIGNED_ALLOC("stxxl::aligned_alloc<" << ALIGNMENT << 00104 ">(size = " << size << ", meta info size = " << meta_info_size << 00105 ") => buffer = " << (void *)buffer << ", ptr = " << (void *)result); 00106 00107 return result; 00108 } 00109 00110 template <size_t ALIGNMENT> 00111 inline void 00112 aligned_dealloc(void * ptr) 00113 { 00114 if (!ptr) 00115 return; 00116 char * buffer = *(((char **)ptr) - 1); 00117 STXXL_VERBOSE_ALIGNED_ALLOC("stxxl::aligned_dealloc<" << ALIGNMENT << ">(), ptr = " << ptr << ", buffer = " << (void *)buffer); 00118 std::free(buffer); 00119 } 00120 00121 __STXXL_END_NAMESPACE 00122 00123 #endif // !STXXL_ALIGNED_ALLOC 00124 // vim: et:ts=4:sw=4