1 ///-*-C++-*-////////////////////////////////////////////////////////////////// 2 // 3 // Hoard: A Fast, Scalable, and Memory-Efficient Allocator 4 // for Shared-Memory Multiprocessors 5 // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery 6 // 7 // Copyright (c) 1998-2000, The University of Texas at Austin. 8 // 9 // This library is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU Library General Public License as 11 // published by the Free Software Foundation, http://www.fsf.org. 12 // 13 // This library is distributed in the hope that it will be useful, but 14 // WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 // Library General Public License for more details. 17 // 18 ////////////////////////////////////////////////////////////////////////////// 19 20 #ifndef _THREADHEAP_H_ 21 #define _THREADHEAP_H_ 22 23 #include "config.h" 24 25 #include <string.h> 26 27 #include "heap.h" 28 29 namespace BPrivate { 30 31 class processHeap; // forward declaration 32 33 // 34 // We use one threadHeap for each thread (processor). 35 // 36 37 class threadHeap : public hoardHeap { 38 public: 39 threadHeap(void); 40 41 // Memory allocation routines. 42 void *malloc(const size_t sz); 43 inline void *memalign(size_t alignment, size_t sz); 44 45 // Find out how large an allocated object is. 46 inline static size_t objectSize(void *ptr); 47 48 // Set our process heap. 49 inline void setpHeap(processHeap *p); 50 51 private: 52 // Prevent copying and assignment. 53 threadHeap(const threadHeap &); 54 const threadHeap &operator=(const threadHeap &); 55 56 // Our process heap. 57 processHeap *_pHeap; 58 59 // We insert a cache pad here to avoid false sharing (the 60 // processHeap holds an array of threadHeaps, and we don't want 61 // these to share any cache lines). 62 double _pad[CACHE_LINE / sizeof(double)]; 63 }; 64 65 66 void * 67 threadHeap::memalign(size_t alignment, size_t size) 68 { 69 // Calculate the amount of space we need 70 // to satisfy the alignment requirements. 71 72 size_t newSize; 73 74 // If the alignment is less than the required alignment, 75 // just call malloc. 76 if (alignment <= ALIGNMENT) 77 return this->malloc(size); 78 79 if (alignment < sizeof(block)) 80 alignment = sizeof(block); 81 82 // Alignment must be a power of two! 83 assert((alignment & (alignment - 1)) == 0); 84 85 // Leave enough room to align the block within the malloced space. 86 newSize = size + sizeof(block) + alignment; 87 88 // Now malloc the space up with a little extra (we'll put the block 89 // pointer in right behind the allocated space). 90 91 void *ptr = this->malloc(newSize); 92 if ((((unsigned long) ptr) & -((long) alignment)) == 0) { 93 // ptr is already aligned, so return it. 94 assert(((unsigned long) ptr % alignment) == 0); 95 return ptr; 96 } else { 97 // Align ptr. 98 char *newptr = (char *)(((unsigned long)ptr + alignment - 1) & -((long)alignment)); 99 100 // If there's not enough room for the block header, skip to the 101 // next aligned space within the block.. 102 if ((unsigned long)newptr - (unsigned long)ptr < sizeof(block)) 103 newptr += alignment; 104 105 assert(((unsigned long)newptr % alignment) == 0); 106 107 // Copy the block from the start of the allocated memory. 108 block *b = ((block *)ptr - 1); 109 110 assert(b->isValid()); 111 assert(b->getSuperblock()->isValid()); 112 113 // Make sure there's enough room for the block header. 114 assert(((unsigned long)newptr - (unsigned long)ptr) >= 115 sizeof(block)); 116 117 block *p = ((block *)newptr - 1); 118 119 // Make sure there's enough room allocated for size bytes. 120 assert(((unsigned long)p - sizeof(block)) >= (unsigned long)b); 121 122 if (p != b) { 123 assert((unsigned long)newptr > (unsigned long)ptr); 124 // Copy the block header. 125 *p = *b; 126 assert(p->isValid()); 127 assert(p->getSuperblock()->isValid()); 128 129 // Set the next pointer to point to b with the 1 bit set. 130 // When this block is freed, it will be treated specially. 131 p->setNext((block *)((unsigned long)b | 1)); 132 } else 133 assert(ptr != newptr); 134 135 assert(((unsigned long)ptr + newSize) >= 136 ((unsigned long)newptr + size)); 137 return newptr; 138 } 139 } 140 141 142 size_t 143 threadHeap::objectSize(void *ptr) 144 { 145 // Find the superblock pointer. 146 block *b = ((block *)ptr - 1); 147 assert(b->isValid()); 148 superblock *sb = b->getSuperblock(); 149 assert(sb); 150 151 // Return the size. 152 return sizeFromClass(sb->getBlockSizeClass()); 153 } 154 155 156 void threadHeap::setpHeap(processHeap *p) 157 { 158 _pHeap = p; 159 } 160 161 } // namespace BPrivate 162 163 #endif // _THREADHEAP_H_ 164