Eneboo - Documentación para desarrolladores
src/hoard/src/heaplayers/experimental/aoffheap.h
Ir a la documentación de este archivo.
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
 Todo Clases Namespaces Archivos Funciones Variables 'typedefs' Enumeraciones Valores de enumeraciones Propiedades Amigas 'defines'