Eneboo - Documentación para desarrolladores
|
00001 /* -*- C++ -*- */ 00002 00003 #ifndef _AOFHEAP_H_ 00004 #define _AOFHEAP_H_ 00005 00006 #include <new> // for placement new 00007 using namespace std; 00008 00009 /* 00010 00011 A very simple address-oriented first-fit heap 00012 with immediate coalescing. 00013 00014 Because the heap is stored as a sorted doubly-linked list, 00015 it's potentially quite expensive: 00016 00017 cost of a malloc = O(f) {# of non-contiguous freed objects} 00018 cost of a free = O(f) {# of non-contiguous freed objects} 00019 00020 Worst-case performance could be improved by using a balanced O(log n) dictionary 00021 (like an RB-tree). Also, the free list is threaded through the objects themselves, 00022 something that can cause O(f) page faults; keeping the free list data structures 00023 separate from the data (and in a contiguous region of memory) would avoid this problem. 00024 00025 */ 00026 00027 // Freed objects of at least FreeThreshold size are freed to the super heap. 00028 00029 template <class SuperHeap, int FreeThreshold> 00030 class AOFFHeap : public SuperHeap { 00031 public: 00032 00033 AOFFHeap (void) 00034 { 00035 freeList.setSize (0); 00036 freeList.setNext (&freeList); 00037 freeList.setPrev (&freeList); 00038 } 00039 00040 ~AOFFHeap (void) { 00041 return; // FIX ME FIX ME FIX ME!!! 00042 // Free everything on the free list. 00043 freedObject * ptr = freeList.getNext(); 00044 while (ptr != &freeList) { 00045 freedObject * prev = ptr; 00046 ptr = ptr->getNext(); 00047 SuperHeap::free (prev); 00048 } 00049 } 00050 00051 void * malloc (size_t sz) { 00052 // printf ("aoffheap malloc sz = %d\n", sz); 00053 assert (isValid()); 00054 assert (sz >= sizeof(freedObject) - sizeof(allocatedObject)); 00055 // Find the first object in the free list that fits. 00056 freedObject * ptr = freeList.getNext(); 00057 while ((ptr != &freeList) && (ptr->getSize() < sz + sizeof(freedObject))) { 00058 ptr = ptr->getNext(); 00059 } 00060 // If there wasn't a big-enough object available on the free list, 00061 // make a new one. 00062 if (ptr == &freeList) { 00063 00064 // printf ("AOFF super malloc(%d)\n", sz + sizeof(allocatedObject)); 00065 00066 void * buf = SuperHeap::malloc (sz + sizeof(allocatedObject)); 00067 if (buf == NULL) { 00068 assert (isValid()); 00069 return NULL; 00070 } 00071 freedObject * newptr 00072 = new (buf) freedObject (sz, NULL, NULL); 00073 assert (size(newptr->getStart()) == sz); 00074 assert (isValid()); 00075 return (void *) newptr->getStart(); 00076 } else { 00077 assert (ptr->getSize() >= sz); 00078 // Remove it from the free list. 00079 freedObject * prev = ptr->getPrev(); 00080 freedObject * next = ptr->getNext(); 00081 assert (prev->isValid()); 00082 assert (next->isValid()); 00083 // If it's bigger than the request size, 00084 // splice it up. 00085 if (ptr->getSize() - sz >= sizeof(freedObject)) { 00086 // There's room for another object. 00087 // Splice it off. 00088 size_t oldSize = ptr->getSize(); 00089 ptr->setSize (sz); 00090 freedObject * splicedObj = new (ptr->getSuccessor()) 00091 freedObject (oldSize - sz - sizeof(freedObject), 00092 prev, 00093 next); 00094 prev->setNext (splicedObj); 00095 next->setPrev (splicedObj); 00096 assert (splicedObj->isValid()); 00097 assert (isValid()); 00098 assert (size(ptr->getStart()) == sz); 00099 return (void *) ptr->getStart(); 00100 } else { 00101 assert (0); 00102 abort(); 00103 // It's just right. 00104 // Just remove it. 00105 prev->setNext (next); 00106 next->setPrev (prev); 00107 assert (isValid()); 00108 assert (size(ptr->getStart()) == sz); 00109 return (void *) ptr->getStart(); 00110 } 00111 } 00112 } 00113 00114 void free (void * p) { 00115 assert (isValid()); 00116 // Put the object back in sorted order (by address). 00117 freedObject * thisObject = (freedObject *) ((char *) p - sizeof(allocatedObject)); 00118 assert (thisObject->getStart() == p); 00119 freedObject * prev = &freeList; 00120 freedObject * next = freeList.getNext(); 00121 while ((next != &freeList) && ((char *) thisObject > (char *) next)) { 00122 prev = next; 00123 next = next->getNext(); 00124 } 00125 // Check if this object is already on the free list 00126 // (i.e., it was already deleted). 00127 if (thisObject == next) { 00128 // printf ("Bad call.\n"); 00129 // Ignore the bad programmer and just walk away... 00130 return; 00131 } 00132 // Now insert this object. 00133 prev->setNext (thisObject); 00134 next->setPrev (thisObject); 00135 thisObject = new (thisObject) freedObject (thisObject->getSize(), prev, next); 00136 // See if we can coalesce. 00137 if (prev->getSuccessor() == thisObject) { 00138 assert (prev != &freeList); 00139 coalesce (prev, thisObject); 00140 thisObject = prev; 00141 assert (thisObject->isValid()); 00142 assert (thisObject->getSize() > 0); 00143 // printf ("coalesced prev with this, new size = %d\n", thisObject->getSize()); 00144 } 00145 if (thisObject->getSuccessor() == next) { 00146 coalesce (thisObject, next); 00147 assert (thisObject->isValid()); 00148 //printf ("coalesced this with next, new size = %d\n", thisObject->getSize()); 00149 } 00150 // If this object is big enough, free it. 00151 if (thisObject->getSize() >= FreeThreshold) { 00152 // printf ("freed this (size = %d)\n", thisObject->getSize()); 00153 freedObject * prev = thisObject->getPrev(); 00154 freedObject * next = thisObject->getNext(); 00155 prev->setNext (next); 00156 next->setPrev (prev); 00157 assert (thisObject->isValid()); 00158 SuperHeap::free (thisObject); 00159 } 00160 assert (isValid()); 00161 } 00162 00163 //protected: 00164 inline static size_t size (void * p) 00165 { 00166 allocatedObject * thisObject = (allocatedObject *) p - 1; 00167 assert (thisObject->isValid()); 00168 return thisObject->getSize(); 00169 } 00170 00171 00172 private: 00173 00174 int isValid (void) { 00175 // March through the whole list and check for validity. 00176 freedObject * ptr = freeList.getNext(); 00177 while (ptr != &freeList) { 00178 freedObject * prev = ptr; 00179 assert (prev->getNext()->getPrev() == prev); 00180 assert (prev->isValid()); 00181 ptr = ptr->getNext(); 00182 } 00183 return 1; 00184 } 00185 00186 class freedObject; 00187 00188 inline void coalesce (freedObject * curr, freedObject * succ) { 00189 // printf ("Coalesce %d with %d\n", curr->getSize(), succ->getSize()); 00190 assert (curr->getSuccessor() == succ); 00191 assert (succ->getPrev() == curr); 00192 assert (curr->getNext() == succ); 00193 curr->setNext (succ->getNext()); 00194 succ->getNext()->setPrev(curr); 00195 curr->setSize (curr->getSize() + succ->getSize() + sizeof(allocatedObject)); 00196 assert (curr->isValid()); 00197 } 00198 inline static size_t align (int sz) { 00199 return (sz + (sizeof(double) - 1)) & ~(sizeof(double) - 1); 00200 } 00201 00202 class allocatedObject { 00203 public: 00204 allocatedObject (void) 00205 { 00206 size = 0; 00207 #ifndef NDEBUG 00208 magic = 0xfacefade; 00209 #endif 00210 } 00211 int isValid (void) const { 00212 return (size >= 0) && (magic == 0xfacefade); 00213 } 00214 void setSize (size_t sz) { size = sz; assert (isValid()); } 00215 int getSize (void) const { assert (isValid()); return size; } 00216 00217 // Return the start of the next object. 00218 allocatedObject * getSuccessor (void) const { 00219 assert (isValid()); 00220 return (allocatedObject *) ((char *) (this + 1) + size); 00221 } 00222 00223 // Return the start of the actual object (beyond the header). 00224 char * getStart (void) const { 00225 assert (isValid()); 00226 return ((char *) (this + 1)); 00227 } 00228 private: 00229 int size; 00230 int magic; 00231 }; 00232 00233 class freedObject : public allocatedObject { 00234 public: 00235 freedObject (void) 00236 : prev ((freedObject *) 0xdeadbeef), 00237 next ((freedObject *) 0xdeadbeef) 00238 {} 00239 freedObject (size_t sz, 00240 freedObject * p, 00241 freedObject * n) 00242 : prev (p), 00243 next (n) 00244 { 00245 allocatedObject::setSize (sz); 00246 } 00247 int isValid (void) const { 00248 return (allocatedObject::isValid()); 00249 } 00250 freedObject * getPrev (void) const { assert (isValid()); return prev; } 00251 freedObject * getNext (void) const { assert (isValid()); return next; } 00252 void setPrev (freedObject * p) { assert (isValid()); prev = p; } 00253 void setNext (freedObject * p) { assert (isValid()); next = p; } 00254 private: 00255 freedObject * prev; 00256 freedObject * next; 00257 }; 00258 00259 00260 freedObject freeList; 00261 double _dummy; // Just to make sure that the freeList node won't ever be coalesced! 00262 }; 00263 00264 #endif