Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison vmalloc.c @ 101:ca154ebe2b6c
Basic malloc without small chunks
| author | Merten Sach <msach@mailbox.tu-berlin.de> |
|---|---|
| date | Tue, 02 Aug 2011 15:44:28 +0200 |
| parents | 21c95d402fe6 |
| children | def70e32cf2c |
comparison
equal
deleted
inserted
replaced
| 12:a0b38c64a0b6 | 13:07daf0c09527 |
|---|---|
| 9 | 9 |
| 10 #include <malloc.h> | 10 #include <malloc.h> |
| 11 #include <inttypes.h> | 11 #include <inttypes.h> |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 #include <stdio.h> | 13 #include <stdio.h> |
| 14 #include <string.h> | |
| 15 #include <math.h> | |
| 14 | 16 |
| 15 #include "VMS.h" | 17 #include "VMS.h" |
| 16 #include "Histogram/Histogram.h" | 18 #include "Histogram/Histogram.h" |
| 17 | 19 |
| 18 /*Helper function | 20 /* |
| 19 *Insert a newly generated free chunk into the first spot on the free list. | 21 * This calculates the container which fits the given size. |
| 20 * The chunk is cast as a MallocProlog, so the various pointers in it are | 22 */ |
| 21 * accessed with C's help -- and the size of the prolog is easily added to | 23 inline |
| 22 * the pointer when a chunk is returned to the app -- so C handles changes | 24 uint32 getContainer(size_t size) |
| 23 * in pointer sizes among machines. | 25 { |
| 24 * | 26 return floor((log10(size)-LOG128)/LOG54); |
| 25 *The list head is a normal MallocProlog struct -- identified by its | 27 } |
| 26 * prevChunkInFreeList being NULL -- the only one. | 28 |
| 27 * | 29 /* |
| 28 *The end of the list is identified by next chunk being NULL, as usual. | 30 * This calculates the size of a given container |
| 29 */ | 31 */ |
| 30 void inline | 32 inline |
| 31 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead ) | 33 size_t getContainerSize(uint32 idx) |
| 32 { | 34 { |
| 33 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList; | 35 return pow(CHUNK_INCREASE_RATE,idx)*LOWER_BOUND; |
| 34 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list | 36 } |
| 35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; | 37 |
| 36 chunk->prevChunkInFreeList = listHead; | 38 /* |
| 37 listHead->nextChunkInFreeList = chunk; | 39 * Removes the first chunk of a freeList |
| 38 } | 40 * The chunk is removed but not set as free. There is no check if |
| 39 | 41 * the free list is empty, so make sure this is not the case. |
| 40 | 42 */ |
| 41 /*This is sequential code, meant to only be called from the Master, not from | 43 inline |
| 44 MallocProlog *removeChunk(MallocProlog** container) | |
| 45 { | |
| 46 MallocProlog *removedChunk = *container; | |
| 47 *container = removedChunk->nextChunkInFreeList; | |
| 48 | |
| 49 if(removedChunk->nextChunkInFreeList) | |
| 50 removedChunk->nextChunkInFreeList->prevChunkInFreeList = | |
| 51 (MallocProlog*)container; | |
| 52 | |
| 53 return removedChunk; | |
| 54 } | |
| 55 | |
| 56 /* | |
| 57 * Removes a chunk from a free list. | |
| 58 */ | |
| 59 inline | |
| 60 MallocProlog *extractChunk(MallocProlog* chunk) | |
| 61 { | |
| 62 | |
| 63 } | |
| 64 | |
| 65 /* | |
| 66 * Merges two chunks. | |
| 67 * Chunk A has to be before chunk B in memory. | |
| 68 */ | |
| 69 inline | |
| 70 MallocProlog *mergeChunks(MallocProlog* chunkA, MallocProlog* chunkB) | |
| 71 { | |
| 72 | |
| 73 } | |
| 74 /* | |
| 75 * Inserts a chunk into a free list. | |
| 76 */ | |
| 77 inline | |
| 78 void insertChunk(MallocProlog* chunk, MallocProlog** container) | |
| 79 { | |
| 80 chunk->nextChunkInFreeList = *container; | |
| 81 chunk->prevChunkInFreeList = (MallocProlog*)container; | |
| 82 if(*container) | |
| 83 (*container)->prevChunkInFreeList = chunk; | |
| 84 *container = chunk; | |
| 85 } | |
| 86 | |
| 87 /* | |
| 88 * Divides the chunk that a new chunk of newSize is created. | |
| 89 * There is no size check, so make sure the size value is valid. | |
| 90 */ | |
| 91 inline | |
| 92 MallocProlog *divideChunk(MallocProlog* chunk, size_t newSize) | |
| 93 { | |
| 94 MallocProlog* newChunk = (MallocProlog*)((uintptr_t)chunk->nextHigherInMem - | |
| 95 newSize - sizeof(MallocProlog)); | |
| 96 | |
| 97 newChunk->nextLowerInMem = chunk; | |
| 98 newChunk->nextHigherInMem = chunk->nextHigherInMem; | |
| 99 | |
| 100 chunk->nextHigherInMem = newChunk; | |
| 101 chunk->nextHigherInMem->nextLowerInMem = newChunk; | |
| 102 | |
| 103 return newChunk; | |
| 104 } | |
| 105 | |
| 106 inline | |
| 107 size_t getChunkSize(MallocProlog* chunk) | |
| 108 { | |
| 109 return (uintptr_t)chunk->nextHigherInMem - | |
| 110 (uintptr_t)chunk - sizeof(MallocProlog); | |
| 111 } | |
| 112 | |
| 113 /* | |
| 114 * This is sequential code, meant to only be called from the Master, not from | |
| 42 * any slave VPs. | 115 * any slave VPs. |
| 43 *Search down list, checking size by the nextHigherInMem pointer, to find | |
| 44 * first chunk bigger than size needed. | |
| 45 *Shave off the extra and make it into a new free-list element, hook it in | |
| 46 * then return the address of the found element plus size of prolog. | |
| 47 * | |
| 48 *Will find a | |
| 49 */ | 116 */ |
| 50 void *VMS__malloc( size_t sizeRequested ) | 117 void *VMS__malloc( size_t sizeRequested ) |
| 51 { MallocProlog *foundElem = NULL, *currElem, *newElem; | 118 { |
| 52 ssize_t amountExtra, sizeConsumed,sizeOfFound; | |
| 53 uint32 foundElemIsTopOfHeap; | |
| 54 | |
| 55 //============================= MEASUREMENT STUFF ======================== | 119 //============================= MEASUREMENT STUFF ======================== |
| 56 #ifdef MEAS__TIME_MALLOC | 120 #ifdef MEAS__TIME_MALLOC |
| 57 int32 startStamp, endStamp; | 121 int32 startStamp, endStamp; |
| 58 saveLowTimeStampCountInto( startStamp ); | 122 saveLowTimeStampCountInto( startStamp ); |
| 59 #endif | 123 #endif |
| 60 //======================================================================== | 124 //======================================================================== |
| 61 | 125 |
| 62 //step up the size to be aligned at 16-byte boundary, prob better ways | 126 MallocArrays* freeList = _VMSMasterEnv->freeLists; |
| 63 sizeRequested = (sizeRequested + 16) & ~15; | 127 |
| 64 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; | 128 //Return a small chunk if the requested size is smaller than 128B |
| 65 | 129 //TODO: for now set size to 129B |
| 66 while( currElem != NULL ) | 130 if(sizeRequested < 128) |
| 67 { //check if size of currElem is big enough | 131 sizeRequested = 129; |
| 68 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); | 132 |
| 69 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); | 133 //Calculate the expected container. Start one higher to have a Chunk that's |
| 70 if( amountExtra > 0 ) | 134 //always big enough. |
| 71 { //found it, get out of loop | 135 uint32 targetContainerIdx = getContainer(sizeRequested); |
| 72 foundElem = currElem; | 136 uint32 containerIdx = targetContainerIdx + 1; |
| 73 currElem = NULL; | 137 |
| 138 MallocProlog* foundChunk; | |
| 139 if(freeList->bigChunks[containerIdx] == NULL) | |
| 140 { | |
| 141 while(freeList->bigChunks[containerIdx] == NULL) | |
| 142 { | |
| 143 containerIdx++; | |
| 144 if(containerIdx > freeList->containerCount) | |
| 145 { | |
| 146 printf("VMS malloc failed: low memory"); | |
| 147 exit(1); | |
| 148 } | |
| 74 } | 149 } |
| 75 else | 150 |
| 76 currElem = currElem->nextChunkInFreeList; | 151 foundChunk = removeChunk(&freeList->bigChunks[containerIdx]); |
| 77 } | 152 //Found bigger Element, so we have to divide until it fits the |
| 78 | 153 //requested size |
| 79 if( foundElem == NULL ) | 154 containerIdx--; |
| 80 { ERROR("\nmalloc failed\n") | 155 size_t containerSize = getContainerSize(containerIdx); |
| 81 return (void *)NULL; //indicates malloc failed | 156 size_t chunkSize = getChunkSize(foundChunk); |
| 82 } | 157 |
| 83 //Using a kludge to identify the element that is the top chunk in the | 158 while(containerIdx > targetContainerIdx) |
| 84 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and | 159 { |
| 85 // save addr of start of heap in head's nextLowerInMem | 160 if(chunkSize > containerSize + sizeRequested + sizeof(MallocProlog)) |
| 86 //Will handle top of Heap specially | 161 { |
| 87 foundElemIsTopOfHeap = foundElem->nextHigherInMem == | 162 MallocProlog *newChunk = divideChunk(foundChunk,containerSize); |
| 88 _VMSMasterEnv->freeListHead->nextHigherInMem; | 163 insertChunk(newChunk,&freeList->bigChunks[containerIdx]); |
| 89 | 164 chunkSize = getChunkSize(foundChunk); |
| 90 //before shave off and try to insert new elem, remove found elem | 165 } |
| 91 //note, foundElem will never be the head, so always has valid prevChunk | 166 containerIdx--; |
| 92 foundElem->prevChunkInFreeList->nextChunkInFreeList = | 167 containerSize /= CHUNK_INCREASE_RATE; |
| 93 foundElem->nextChunkInFreeList; | 168 } |
| 94 if( foundElem->nextChunkInFreeList != NULL ) | 169 } |
| 95 { foundElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 96 foundElem->prevChunkInFreeList; | |
| 97 } | |
| 98 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | |
| 99 | |
| 100 //if enough, turn extra into new elem & insert it | |
| 101 if( amountExtra > 64 ) | |
| 102 { //make new elem by adding to addr of curr elem then casting | |
| 103 sizeConsumed = sizeof(MallocProlog) + sizeRequested; | |
| 104 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); | |
| 105 newElem->nextLowerInMem = foundElem; //This is evil (but why?) | |
| 106 newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?) | |
| 107 foundElem->nextHigherInMem = newElem; | |
| 108 if( ! foundElemIsTopOfHeap ) | |
| 109 { //there is no next higher for top of heap, so can't write to it | |
| 110 newElem->nextHigherInMem->nextLowerInMem = newElem; | |
| 111 } | |
| 112 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); | |
| 113 } | |
| 114 else | 170 else |
| 115 { | 171 { |
| 116 sizeConsumed = sizeOfFound; | 172 foundChunk = removeChunk(&freeList->bigChunks[containerIdx]); |
| 117 } | 173 } |
| 118 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; | 174 |
| 119 | 175 //Mark as allocated |
| 176 foundChunk->prevChunkInFreeList = NULL; | |
| 177 | |
| 120 //============================= MEASUREMENT STUFF ======================== | 178 //============================= MEASUREMENT STUFF ======================== |
| 121 #ifdef MEAS__TIME_MALLOC | 179 #ifdef MEAS__TIME_MALLOC |
| 122 saveLowTimeStampCountInto( endStamp ); | 180 saveLowTimeStampCountInto( endStamp ); |
| 123 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); | 181 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); |
| 124 #endif | 182 #endif |
| 125 //======================================================================== | 183 //======================================================================== |
| 126 | 184 |
| 127 //skip over the prolog by adding its size to the pointer return | 185 //skip over the prolog by adding its size to the pointer return |
| 128 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); | 186 return (void*)((uintptr_t)foundChunk + sizeof(MallocProlog)); |
| 129 } | 187 } |
| 130 | 188 |
| 131 /*This is sequential code, meant to only be called from the Master, not from | 189 /* |
| 190 * This is sequential code, meant to only be called from the Master, not from | |
| 132 * any slave VPs. | 191 * any slave VPs. |
| 133 *Search down list, checking size by the nextHigherInMem pointer, to find | |
| 134 * first chunk bigger than size needed. | |
| 135 *Shave off the extra and make it into a new free-list element, hook it in | |
| 136 * then return the address of the found element plus size of prolog. | |
| 137 * | |
| 138 * The difference to the regular malloc is, that all the allocated chunks are | |
| 139 * aligned and padded to the size of a CACHE_LINE. Thus creating a new chunk | |
| 140 * before the aligned chunk. | |
| 141 */ | |
| 142 void *VMS__malloc_aligned( size_t sizeRequested ) | |
| 143 { MallocProlog *foundElem = NULL, *currElem, *newElem; | |
| 144 ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount; | |
| 145 uint32 foundElemIsTopOfHeap; | |
| 146 | |
| 147 //============================= MEASUREMENT STUFF ======================== | |
| 148 #ifdef MEAS__TIME_MALLOC | |
| 149 uint32 startStamp, endStamp; | |
| 150 saveLowTimeStampCountInto( startStamp ); | |
| 151 #endif | |
| 152 //======================================================================== | |
| 153 | |
| 154 //step up the size to be multiple of the cache line size | |
| 155 sizeRequested = (sizeRequested + CACHE_LINE) & ~(CACHE_LINE-1); | |
| 156 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; | |
| 157 | |
| 158 while( currElem != NULL ) | |
| 159 { //check if size of currElem is big enough | |
| 160 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); | |
| 161 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); | |
| 162 if( amountExtra > 0 ) | |
| 163 { | |
| 164 //look if the found element is already aligned | |
| 165 if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE-1)) == 0){ | |
| 166 //found it, get out of loop | |
| 167 foundElem = currElem; | |
| 168 break; | |
| 169 }else{ | |
| 170 //find first aligned address and check if it's still big enough | |
| 171 //check also if the space before the aligned address is big enough | |
| 172 //for a new element | |
| 173 void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE) & ~((uintptr_t)(CACHE_LINE-1))); | |
| 174 prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem; | |
| 175 sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog); | |
| 176 amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog); | |
| 177 if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){ | |
| 178 //found suitable element | |
| 179 //create new previous element and exit loop | |
| 180 MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1; | |
| 181 | |
| 182 //insert new element into free list | |
| 183 if(currElem->nextChunkInFreeList != NULL) | |
| 184 currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem; | |
| 185 newAlignedElem->prevChunkInFreeList = currElem; | |
| 186 newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList; | |
| 187 currElem->nextChunkInFreeList = newAlignedElem; | |
| 188 | |
| 189 //set higherInMem and lowerInMem | |
| 190 newAlignedElem->nextHigherInMem = currElem->nextHigherInMem; | |
| 191 foundElemIsTopOfHeap = currElem->nextHigherInMem == | |
| 192 _VMSMasterEnv->freeListHead->nextHigherInMem; | |
| 193 if(!foundElemIsTopOfHeap) | |
| 194 currElem->nextHigherInMem->nextLowerInMem = newAlignedElem; | |
| 195 currElem->nextHigherInMem = newAlignedElem; | |
| 196 newAlignedElem->nextLowerInMem = currElem; | |
| 197 | |
| 198 //Found new element leaving loop | |
| 199 foundElem = newAlignedElem; | |
| 200 break; | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 } | |
| 205 currElem = currElem->nextChunkInFreeList; | |
| 206 } | |
| 207 | |
| 208 if( foundElem == NULL ) | |
| 209 { ERROR("\nmalloc failed\n") | |
| 210 return (void *)NULL; //indicates malloc failed | |
| 211 } | |
| 212 //Using a kludge to identify the element that is the top chunk in the | |
| 213 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and | |
| 214 // save addr of start of heap in head's nextLowerInMem | |
| 215 //Will handle top of Heap specially | |
| 216 foundElemIsTopOfHeap = foundElem->nextHigherInMem == | |
| 217 _VMSMasterEnv->freeListHead->nextHigherInMem; | |
| 218 | |
| 219 //before shave off and try to insert new elem, remove found elem | |
| 220 //note, foundElem will never be the head, so always has valid prevChunk | |
| 221 foundElem->prevChunkInFreeList->nextChunkInFreeList = | |
| 222 foundElem->nextChunkInFreeList; | |
| 223 if( foundElem->nextChunkInFreeList != NULL ) | |
| 224 { foundElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 225 foundElem->prevChunkInFreeList; | |
| 226 } | |
| 227 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | |
| 228 | |
| 229 //if enough, turn extra into new elem & insert it | |
| 230 if( amountExtra > 64 ) | |
| 231 { //make new elem by adding to addr of curr elem then casting | |
| 232 sizeConsumed = sizeof(MallocProlog) + sizeRequested; | |
| 233 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); | |
| 234 newElem->nextHigherInMem = foundElem->nextHigherInMem; | |
| 235 newElem->nextLowerInMem = foundElem; | |
| 236 foundElem->nextHigherInMem = newElem; | |
| 237 | |
| 238 if( ! foundElemIsTopOfHeap ) | |
| 239 { //there is no next higher for top of heap, so can't write to it | |
| 240 newElem->nextHigherInMem->nextLowerInMem = newElem; | |
| 241 } | |
| 242 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); | |
| 243 } | |
| 244 else | |
| 245 { | |
| 246 sizeConsumed = sizeOfFound; | |
| 247 } | |
| 248 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; | |
| 249 | |
| 250 //============================= MEASUREMENT STUFF ======================== | |
| 251 #ifdef MEAS__TIME_MALLOC | |
| 252 saveLowTimeStampCountInto( endStamp ); | |
| 253 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); | |
| 254 #endif | |
| 255 //======================================================================== | |
| 256 | |
| 257 //skip over the prolog by adding its size to the pointer return | |
| 258 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); | |
| 259 } | |
| 260 | |
| 261 | |
| 262 /*This is sequential code -- only to be called from the Master | |
| 263 * When free, subtract the size of prolog from pointer, then cast it to a | |
| 264 * MallocProlog. Then check the nextLower and nextHigher chunks to see if | |
| 265 * one or both are also free, and coalesce if so, and if neither free, then | |
| 266 * add this one to free-list. | |
| 267 */ | 192 */ |
| 268 void | 193 void |
| 269 VMS__free( void *ptrToFree ) | 194 VMS__free( void *ptrToFree ) |
| 270 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; | 195 { |
| 271 size_t sizeOfElem; | |
| 272 uint32 lowerExistsAndIsFree, higherExistsAndIsFree; | |
| 273 | 196 |
| 274 //============================= MEASUREMENT STUFF ======================== | 197 //============================= MEASUREMENT STUFF ======================== |
| 275 #ifdef MEAS__TIME_MALLOC | 198 #ifdef MEAS__TIME_MALLOC |
| 276 int32 startStamp, endStamp; | 199 int32 startStamp, endStamp; |
| 277 saveLowTimeStampCountInto( startStamp ); | 200 saveLowTimeStampCountInto( startStamp ); |
| 278 #endif | 201 #endif |
| 279 //======================================================================== | 202 //======================================================================== |
| 280 | 203 |
| 281 if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem || | 204 MallocArrays* freeList = _VMSMasterEnv->freeLists; |
| 282 ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem ) | 205 MallocProlog *chunkToFree = (MallocProlog*)ptrToFree - 1; |
| 283 { //outside the range of data owned by VMS's malloc, so do nothing | 206 |
| 284 return; | 207 //Check for free neighbors |
| 285 } | 208 if(chunkToFree->nextLowerInMem) |
| 286 //subtract size of prolog to get pointer to prolog, then cast | 209 { |
| 287 elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog)); | 210 if(chunkToFree->nextLowerInMem->prevChunkInFreeList != NULL) |
| 288 sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree); | 211 {//Chunk is not allocated |
| 289 | 212 mergeChunks() |
| 290 if( elemToFree->prevChunkInFreeList != NULL ) | |
| 291 { printf( "error: freeing same element twice!" ); exit(1); | |
| 292 } | |
| 293 | |
| 294 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem; | |
| 295 | |
| 296 nextLowerElem = elemToFree->nextLowerInMem; | |
| 297 nextHigherElem = elemToFree->nextHigherInMem; | |
| 298 | |
| 299 if( nextHigherElem == NULL ) | |
| 300 higherExistsAndIsFree = FALSE; | |
| 301 else //okay exists, now check if in the free-list by checking back ptr | |
| 302 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL); | |
| 303 | |
| 304 if( nextLowerElem == NULL ) | |
| 305 lowerExistsAndIsFree = FALSE; | |
| 306 else //okay, it exists, now check if it's free | |
| 307 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL); | |
| 308 | |
| 309 | |
| 310 //now, know what exists and what's free | |
| 311 if( lowerExistsAndIsFree ) | |
| 312 { if( higherExistsAndIsFree ) | |
| 313 { //both exist and are free, so coalesce all three | |
| 314 //First, remove higher from free-list | |
| 315 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList = | |
| 316 nextHigherElem->nextChunkInFreeList; | |
| 317 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list? | |
| 318 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 319 nextHigherElem->prevChunkInFreeList; | |
| 320 //Now, fix-up sequence-in-mem list -- by side-effect, this also | |
| 321 // changes size of the lower elem, which is still in free-list | |
| 322 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem; | |
| 323 if( nextHigherElem->nextHigherInMem != | |
| 324 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 325 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem; | |
| 326 //notice didn't do anything to elemToFree -- it simply is no | |
| 327 // longer reachable from any of the lists. Wonder if could be a | |
| 328 // security leak because left valid addresses in it, | |
| 329 // but don't care for now. | |
| 330 } | 213 } |
| 331 else | 214 } |
| 332 { //lower is the only of the two that exists and is free, | |
| 333 //In this case, no adjustment to free-list, just change mem-list. | |
| 334 // By side-effect, changes size of the lower elem | |
| 335 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem; | |
| 336 if( elemToFree->nextHigherInMem != | |
| 337 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 338 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem; | |
| 339 } | |
| 340 } | |
| 341 else | |
| 342 { //lower either doesn't exist or isn't free, so check higher | |
| 343 if( higherExistsAndIsFree ) | |
| 344 { //higher exists and is the only of the two free | |
| 345 //First, in free-list, replace higher elem with the one to free | |
| 346 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList; | |
| 347 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList; | |
| 348 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree; | |
| 349 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? | |
| 350 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; | |
| 351 //Now chg mem-list. By side-effect, changes size of elemToFree | |
| 352 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem; | |
| 353 if( elemToFree->nextHigherInMem != | |
| 354 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 355 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree; | |
| 356 } | |
| 357 else | |
| 358 { //neither lower nor higher is availabe to coalesce so add to list | |
| 359 // this makes prev chunk ptr non-null, which indicates it's free | |
| 360 elemToFree->nextChunkInFreeList = | |
| 361 _VMSMasterEnv->freeListHead->nextChunkInFreeList; | |
| 362 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree; | |
| 363 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? | |
| 364 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; | |
| 365 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead; | |
| 366 } | |
| 367 } | |
| 368 //============================= MEASUREMENT STUFF ======================== | 215 //============================= MEASUREMENT STUFF ======================== |
| 369 #ifdef MEAS__TIME_MALLOC | 216 #ifdef MEAS__TIME_MALLOC |
| 370 saveLowTimeStampCountInto( endStamp ); | 217 saveLowTimeStampCountInto( endStamp ); |
| 371 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist ); | 218 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist ); |
| 372 #endif | 219 #endif |
| 438 } | 285 } |
| 439 | 286 |
| 440 | 287 |
| 441 /*Designed to be called from the main thread outside of VMS, during init | 288 /*Designed to be called from the main thread outside of VMS, during init |
| 442 */ | 289 */ |
| 443 MallocProlog * | 290 MallocArrays * |
| 444 VMS_ext__create_free_list() | 291 VMS_ext__create_free_list() |
| 445 { MallocProlog *freeListHead, *firstChunk; | 292 { |
| 446 | 293 //Initialize containers for small chunks and fill with zeros |
| 447 //Note, this is running in the main thread -- all increases in malloc | 294 _VMSMasterEnv->freeLists = (MallocArrays*)malloc( sizeof(MallocArrays) ); |
| 448 // mem and all frees of it must be done in this thread, with the | 295 MallocArrays *freeLists = _VMSMasterEnv->freeLists; |
| 449 // thread's original stack available | 296 |
| 450 freeListHead = malloc( sizeof(MallocProlog) ); | 297 freeLists->smallChunks = |
| 451 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); | 298 (MallocProlog**)malloc(SMALL_CHUNK_COUNT*sizeof(MallocProlog*)); |
| 299 memset((void*)freeLists->smallChunks, | |
| 300 0,SMALL_CHUNK_COUNT*sizeof(MallocProlog*)); | |
| 301 | |
| 302 //Calculate number of containers for big chunks | |
| 303 uint32 container = getContainer(MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE)+1; | |
| 304 | |
| 305 freeLists->bigChunks = (MallocProlog**)malloc(container*sizeof(MallocProlog*)); | |
| 306 memset((void*)freeLists->bigChunks,0,container*sizeof(MallocProlog*)); | |
| 307 freeLists->containerCount = container; | |
| 308 | |
| 309 //Create first element in lastContainer | |
| 310 MallocProlog *firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); | |
| 452 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);} | 311 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);} |
| 453 | 312 |
| 454 //Touch memory to avoid page faults | 313 firstChunk->nextLowerInMem = NULL; |
| 455 void *ptr,*endPtr; | 314 firstChunk->nextHigherInMem = (MallocProlog*)((uintptr_t)firstChunk + |
| 456 endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE; | 315 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE - sizeof(MallocProlog*)); |
| 457 for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE) | 316 firstChunk->nextChunkInFreeList = NULL; |
| 458 { | 317 //previous element in the queue is the container |
| 459 *(char*)ptr = 0; | 318 firstChunk->prevChunkInFreeList = freeLists->bigChunks[container-1]; |
| 460 } | 319 |
| 461 | 320 freeLists->bigChunks[container-1] = firstChunk; |
| 462 freeListHead->prevChunkInFreeList = NULL; | 321 |
| 463 //Use this addr to free the heap when cleanup | 322 //Create dummy chunk to mark the top of stack this is of course |
| 464 freeListHead->nextLowerInMem = firstChunk; | 323 //never freed |
| 465 //to identify top-of-heap elem, compare this addr to elem's next higher | 324 MallocProlog *dummyChunk = firstChunk->nextHigherInMem; |
| 466 freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk + | 325 dummyChunk->nextHigherInMem = dummyChunk+1; |
| 467 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE); | 326 dummyChunk->nextLowerInMem = NULL; |
| 468 freeListHead->nextChunkInFreeList = firstChunk; | 327 dummyChunk->nextChunkInFreeList = NULL; |
| 469 | 328 dummyChunk->prevChunkInFreeList = NULL; |
| 470 firstChunk->nextChunkInFreeList = NULL; | 329 |
| 471 firstChunk->prevChunkInFreeList = freeListHead; | 330 return freeLists; |
| 472 //next Higher has to be set to top of chunk, so can calc size in malloc | |
| 473 firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk + | |
| 474 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE); | |
| 475 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap | |
| 476 | |
| 477 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet | |
| 478 | |
| 479 return freeListHead; | |
| 480 } | 331 } |
| 481 | 332 |
| 482 | 333 |
| 483 /*Designed to be called from the main thread outside of VMS, during cleanup | 334 /*Designed to be called from the main thread outside of VMS, during cleanup |
| 484 */ | 335 */ |
