Eneboo - Documentación para desarrolladores
|
00001 /* -*- C++ -*- */ 00002 00003 #ifndef _LOOSESLOTHEAP_H_ 00004 #define _LOOSESLOTHEAP_H_ 00005 00006 #include <assert.h> 00007 00008 #include "bigchunk.h" 00009 00010 /* 00011 LooseSlotHeap: A "Loose" slot heap. 00012 00013 malloc returns objects of size slotSize, allocated from the super heap 00014 in chunkSize units. 00015 00016 free returns objects of size slotSize. 00017 00018 When the slot heap is at least 1/emptyFraction empty, a 00019 chunk that is at least that empty is freed to the super heap. 00020 Note that the chunk's memory MAY NOT SAFELY be recycled in toto -- 00021 it must be parceled out using the chunk interface. 00022 00023 The intent of this heap is to allow mostly-empty chunks to move up 00024 to a staging area (the super heap) where they may be reused by other 00025 "loose" slot heaps. 00026 00027 */ 00028 00029 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00030 class LooseSlotHeap { 00031 public: 00032 00033 inline LooseSlotHeap (void); 00034 inline ~LooseSlotHeap (void); 00035 00036 // Get a slotSize object. 00037 inline void * malloc (size_t sz); 00038 00039 // Free a slotSize object. 00040 static inline void free (void * ptr); 00041 00042 private: 00043 00044 Super theHeap; 00045 00046 typedef BigChunk<chunkSize, slotSize, LooseSlotHeap> chunkType; 00047 00048 inline void localFree (void * ptr); 00049 00050 void checkClassInvariant (void) { 00051 #ifndef NDEBUG 00052 assert (inUse >= 0); 00053 assert (inUse <= space); 00054 assert (lastIndex >= 0); 00055 assert (lastIndex <= emptyFraction); 00056 // Now check to make sure that inUse & space are correct. 00057 int localInUse = 0; 00058 int localSpace = 0; 00059 for (int i = 0; i < emptyFraction + 1; i++) { 00060 chunkType * ch = myChunks[i]; 00061 while (ch != NULL) { 00062 assert (ch->getHeap() == this); 00063 localInUse += ch->getNumSlotsInUse(); 00064 localSpace += ch->getNumSlots(); 00065 ch = ch->getNext(); 00066 } 00067 } 00068 assert (localSpace == space); 00069 assert (localInUse == inUse); 00070 #endif 00071 } 00072 00073 // How full is this block? 00074 // 0 == empty to no more than 1/emptyFraction full. 00075 // emptyFraction == completely full. 00076 static inline int getFullness (chunkType * ch); 00077 00078 // Move a chunk, if necessary, into the right list 00079 // based on its emptiness. 00080 // Returns the index of which list it is put or left in. 00081 inline int update (chunkType * ch, int prevIndex); 00082 00083 // The array of chunks, "radix sorted" by emptiness. 00084 // completely empty chunks are in index 0. 00085 // completely full chunks are in index emptyFraction. 00086 chunkType * myChunks[emptyFraction + 1]; 00087 00088 // The last index (from 0) in the above array that has a chunk. 00089 int lastIndex; 00090 00091 // How much space is in use in all of the chunks. 00092 int inUse; 00093 00094 // How much space there is (free or not) in all of the chunks. 00095 int space; 00096 }; 00097 00098 00099 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00100 LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::LooseSlotHeap (void) 00101 : space (0), 00102 inUse (0), 00103 lastIndex (emptyFraction - 1) 00104 { 00105 // Initialize the chunk pointers (all initially empty). 00106 for (int i = 0; i < emptyFraction + 1; i++) { 00107 myChunks[i] = NULL; 00108 } 00109 } 00110 00111 00112 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00113 LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::~LooseSlotHeap (void) 00114 { 00115 // Free every chunk. 00116 chunkType * ch, * tmp; 00117 for (int i = 0; i < emptyFraction + 1; i++) { 00118 ch = myChunks[i]; 00119 while (ch != NULL) { 00120 tmp = ch; 00121 ch = ch->getNext(); 00122 theHeap.free (tmp); 00123 } 00124 } 00125 } 00126 00127 00128 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00129 int LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::getFullness (chunkType * ch) 00130 { 00131 int fullness = (emptyFraction * ch->getNumSlotsInUse())/ch->getNumSlots(); 00132 //printf ("numslots avail = %d, num slots total = %d, fullness = %d\n", ch->getNumSlotsFree(), ch->getNumSlots(), fullness); 00133 return fullness; 00134 } 00135 00136 00137 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00138 void * LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::malloc (size_t sz) 00139 { 00140 checkClassInvariant(); 00141 //printf ("Loose malloc %d (slot size = %d)\n", sz, slotSize); 00142 assert (sz <= slotSize); 00143 void * ptr = NULL; 00144 chunkType * ch = NULL; 00145 // Always try to allocate from the most-full chunk (resetting 00146 // lastIndex as we go). 00147 lastIndex = emptyFraction - 1; // FIX ME! 00148 while (lastIndex >= 0) { 00149 ch = myChunks[lastIndex]; 00150 if (ch == NULL) { 00151 lastIndex--; 00152 } else { 00153 // Got one. 00154 break; 00155 } 00156 } 00157 if (lastIndex < 0) { 00158 assert (ch == NULL); 00159 // There were no chunks available. 00160 assert ((space - inUse) == 0); 00161 // Make one with memory from the "super" heap. 00162 printf ("!!!\n"); 00163 ch = (chunkType*) theHeap.malloc (chunkSize); 00164 ch->setHeap (this); 00165 assert (ch->getNumSlotsFree() > 0); 00166 printf ("Super malloc %d\n", chunkSize); 00167 lastIndex = getFullness(ch); 00168 register chunkType*& head = myChunks[lastIndex]; 00169 assert (head == NULL); 00170 ch->setPrev (NULL); 00171 ch->setNext (NULL); 00172 head = ch; 00173 inUse += ch->getNumSlotsInUse(); 00174 space += ch->getNumSlots(); 00175 assert (ch->getNumSlotsFree() <= ch->getNumSlots()); 00176 // FOR NOW!! FIX ME!!! 00177 assert (ch->getNumSlotsFree() == ch->getNumSlots()); 00178 printf ("Space, in use was %d, %d\n", space, inUse); 00179 printf ("Space, in use NOW %d, %d\n", space, inUse); 00180 } 00181 assert (ch != NULL); 00182 assert (ch->getNumSlotsFree() > 0); 00183 int prevFullness = getFullness (ch); 00184 int prevInUse = ch->getNumSlotsInUse(); 00185 assert (ch->getHeap() == this); 00186 ptr = ch->getSlot(); 00187 inUse++; 00188 assert (prevInUse + 1 == ch->getNumSlotsInUse()); 00189 int newFullness = getFullness (ch); 00190 if (prevFullness != newFullness) { 00191 int n = update (ch, prevFullness); 00192 assert (n == newFullness); 00193 } 00194 chunkType * bch = (chunkType *) chunkType::getChunk(ptr); 00195 assert (bch == ch); 00196 assert (ptr != NULL); 00197 checkClassInvariant(); 00198 return ptr; 00199 } 00200 00201 00202 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00203 void LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::free (void * ptr) { 00204 chunkType * ch 00205 = (chunkType *) chunkType::getChunk (ptr); 00206 assert (ch != NULL); 00207 (ch->getHeap())->localFree (ptr); 00208 } 00209 00210 00211 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00212 void LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::localFree (void * ptr) { 00213 checkClassInvariant(); 00214 printf ("free! (in use = %d, space = %d)\n", inUse, space); 00215 // Mark the slot in the chunk as free. 00216 chunkType * ch 00217 = (chunkType *) chunkType::getChunk (ptr); 00218 assert (ch != NULL); 00219 assert (ch->getHeap() == this); 00220 int prevFullness = getFullness (ch); 00221 int prevInUse = ch->getNumSlotsInUse(); 00222 ch->putSlot (ptr); 00223 inUse--; 00224 assert (prevInUse - 1 == ch->getNumSlotsInUse()); 00225 checkClassInvariant(); 00226 int newIndex = getFullness (ch); 00227 if (prevFullness != newIndex) { 00228 int n = update (ch, prevFullness); 00229 assert (n == newIndex); 00230 } 00231 // If we are more than 1/emptyFraction empty, 00232 // return a mostly-empty chunk to the super heap. 00233 if ((space - inUse > 2 * chunkSize/slotSize) 00234 && (emptyFraction * (space - inUse) > space)) { 00235 printf ("RETURNING A CHUNK!\n"); 00236 // Find an empty chunk. 00237 int emptyIndex = 0; 00238 ch = NULL; 00239 while (emptyIndex < emptyFraction) { 00240 ch = myChunks[emptyIndex]; 00241 if (ch != NULL) 00242 break; 00243 emptyIndex++; 00244 } 00245 assert (ch != NULL); 00246 checkClassInvariant(); 00247 ch->setHeap (NULL); 00248 // Remove a chunk and give it to the super heap. 00249 myChunks[emptyIndex] = myChunks[emptyIndex]->getNext(); 00250 if (myChunks[emptyIndex] != NULL) { 00251 myChunks[emptyIndex]->setPrev (NULL); 00252 } 00253 ch->setPrev (NULL); 00254 ch->setNext (NULL); 00255 // A sanity check on the chunk we're about to return. 00256 assert (ch->getNumSlotsFree() >= 0); 00257 assert (ch->getNumSlots() >= ch->getNumSlotsFree()); 00258 printf ("Updating space & in use: was %d, %d (slots in use = %d)\n", 00259 space, inUse, ch->getNumSlotsInUse()); 00260 space -= ch->getNumSlots(); 00261 inUse -= ch->getNumSlotsInUse(); 00262 printf ("Updating space & in use: NOW %d, %d\n", space, inUse); 00263 theHeap.free (ch); 00264 checkClassInvariant(); 00265 } 00266 checkClassInvariant(); 00267 } 00268 00269 00270 // Move a chunk, if necessary, into the right list 00271 // based on its emptiness. 00272 template <int chunkSize, int slotSize, int emptyFraction, class Super> 00273 int LooseSlotHeap<chunkSize, slotSize, emptyFraction, Super>::update (chunkType * ch, int prevIndex) 00274 { 00275 // Move this chunk if necessary. 00276 #ifndef NDEBUG 00277 chunkType * bch = myChunks[prevIndex]; 00278 while (bch != NULL) { 00279 if (bch == ch) 00280 break; 00281 bch = bch->getNext(); 00282 } 00283 assert (bch == ch); 00284 #endif 00285 int newIndex = getFullness(ch); 00286 // printf ("newIndex = %d\n", newIndex); 00287 // Reset last index (for simplicity). // FIX ME?? 00288 // Remove the chunk from its current list. 00289 if (ch == myChunks[prevIndex]) { 00290 myChunks[prevIndex] = myChunks[prevIndex]->getNext(); 00291 } 00293 if (ch->getPrev() != NULL) { 00294 ch->getPrev()->setNext(ch->getNext()); 00295 } 00296 if (ch->getNext() != NULL) { 00297 ch->getNext()->setPrev(ch->getPrev()); 00298 } 00299 // Add it to the newIndex list. 00300 chunkType*& head = myChunks[newIndex]; 00301 ch->setPrev (NULL); 00302 ch->setNext (head); 00303 if (head != NULL) { 00304 head->setPrev(ch); 00305 } 00306 head = ch; 00307 // Verify that the chunk is in the right list. 00308 #ifndef NDEBUG 00309 bch = myChunks[newIndex]; 00310 while (bch != NULL) { 00311 if (bch == ch) 00312 break; 00313 bch = bch->getNext(); 00314 } 00315 assert (bch == ch); 00316 #endif 00317 return newIndex; 00318 } 00319 00320 00321 00322 #endif