Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison vmalloc.c @ 50:8f7141a9272e
Added VMS__malloc and probes, and major re-factoring to separate mallocs
| author | Me |
|---|---|
| date | Sat, 30 Oct 2010 20:54:36 -0700 |
| parents | |
| children | 42dd44df1bb0 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d69b822a5b7a |
|---|---|
| 1 /* | |
| 2 * Copyright 2009 OpenSourceCodeStewardshipFoundation.org | |
| 3 * Licensed under GNU General Public License version 2 | |
| 4 * | |
| 5 * Author: seanhalle@yahoo.com | |
| 6 * | |
| 7 * Created on November 14, 2009, 9:07 PM | |
| 8 */ | |
| 9 | |
| 10 #include <malloc.h> | |
| 11 | |
| 12 #include "VMS.h" | |
| 13 | |
| 14 /*Helper function | |
| 15 *Insert a newly generated free chunk into the first spot on the free list. | |
| 16 * The chunk is cast as a MallocProlog, so the various pointers in it are | |
| 17 * accessed with C's help -- and the size of the prolog is easily added to | |
| 18 * the pointer when a chunk is returned to the app -- so C handles changes | |
| 19 * in pointer sizes among machines. | |
| 20 * | |
| 21 *The list head is a normal MallocProlog struct -- identified by its | |
| 22 * prevChunkInFreeList being NULL -- the only one. | |
| 23 * | |
| 24 *The end of the list is identified by next chunk being NULL, as usual. | |
| 25 */ | |
| 26 void inline | |
| 27 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead ) | |
| 28 { | |
| 29 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList; | |
| 30 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list | |
| 31 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; | |
| 32 chunk->prevChunkInFreeList = listHead; | |
| 33 listHead->nextChunkInFreeList = chunk; | |
| 34 } | |
| 35 | |
| 36 | |
| 37 /*This is sequential code, meant to only be called from the Master, not from | |
| 38 * any slave VPs. | |
| 39 *Search down list, checking size by the nextHigherInMem pointer, to find | |
| 40 * first chunk bigger than size needed. | |
| 41 *Shave off the extra and make it into a new free-list element, hook it in | |
| 42 * then return the address of the found element plus size of prolog. | |
| 43 * | |
| 44 *Will find a | |
| 45 */ | |
| 46 void * | |
| 47 VMS__malloc( int32 sizeRequested ) | |
| 48 { MallocProlog *foundElem = NULL, *currElem, *newElem; | |
| 49 int32 amountExtra, foundElemIsTopOfHeap, sizeConsumed,sizeOfFound; | |
| 50 | |
| 51 //step up the size to be aligned at 16-byte boundary, prob better ways | |
| 52 sizeRequested = ((sizeRequested + 16) >> 4) << 4; | |
| 53 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; | |
| 54 | |
| 55 while( currElem != NULL ) | |
| 56 { //check if size of currElem is big enough | |
| 57 sizeOfFound=(int32)((char*)currElem->nextHigherInMem -(char*)currElem); | |
| 58 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); | |
| 59 if( amountExtra > 0 ) | |
| 60 { //found it, get out of loop | |
| 61 foundElem = currElem; | |
| 62 currElem = NULL; | |
| 63 } | |
| 64 else | |
| 65 currElem = currElem->nextChunkInFreeList; | |
| 66 } | |
| 67 | |
| 68 if( foundElem == NULL ) | |
| 69 { PRINT_ERROR("\nmalloc failed\n") | |
| 70 return NULL; //indicates malloc failed | |
| 71 } | |
| 72 //Using a kludge to identify the element that is the top chunk in the | |
| 73 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and | |
| 74 // save addr of start of heap in head's nextLowerInMem | |
| 75 //Will handle top of Heap specially | |
| 76 foundElemIsTopOfHeap = foundElem->nextHigherInMem == | |
| 77 _VMSMasterEnv->freeListHead->nextHigherInMem; | |
| 78 | |
| 79 //before shave off and try to insert new elem, remove found elem | |
| 80 //note, foundElem will never be the head, so always has valid prevChunk | |
| 81 foundElem->prevChunkInFreeList->nextChunkInFreeList = | |
| 82 foundElem->nextChunkInFreeList; | |
| 83 if( foundElem->nextChunkInFreeList != NULL ) | |
| 84 { foundElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 85 foundElem->prevChunkInFreeList; | |
| 86 } | |
| 87 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | |
| 88 | |
| 89 //if enough, turn extra into new elem & insert it | |
| 90 if( amountExtra > 64 ) | |
| 91 { //make new elem by adding to addr of curr elem then casting | |
| 92 sizeConsumed = sizeof(MallocProlog) + sizeRequested; | |
| 93 newElem = (MallocProlog *)( (char *)foundElem + sizeConsumed ); | |
| 94 newElem->nextHigherInMem = foundElem->nextHigherInMem; | |
| 95 newElem->nextLowerInMem = foundElem; | |
| 96 foundElem->nextHigherInMem = newElem; | |
| 97 | |
| 98 if( ! foundElemIsTopOfHeap ) | |
| 99 { //there is no next higher for top of heap, so can't write to it | |
| 100 newElem->nextHigherInMem->nextLowerInMem = newElem; | |
| 101 } | |
| 102 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); | |
| 103 } | |
| 104 else | |
| 105 { | |
| 106 sizeConsumed = sizeOfFound; | |
| 107 } | |
| 108 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; | |
| 109 | |
| 110 //skip over the prolog by adding its size to the pointer return | |
| 111 return (void *)((char *)foundElem + sizeof(MallocProlog)); | |
| 112 } | |
| 113 | |
| 114 | |
| 115 /*This is sequential code -- only to be called from the Master | |
| 116 * When free, subtract the size of prolog from pointer, then cast it to a | |
| 117 * MallocProlog. Then check the nextLower and nextHigher chunks to see if | |
| 118 * one or both are also free, and coalesce if so, and if neither free, then | |
| 119 * add this one to free-list. | |
| 120 */ | |
| 121 void | |
| 122 VMS__free( void *ptrToFree ) | |
| 123 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; | |
| 124 int32 lowerExistsAndIsFree, higherExistsAndIsFree, sizeOfElem; | |
| 125 | |
| 126 if( ptrToFree < _VMSMasterEnv->freeListHead->nextLowerInMem || | |
| 127 ptrToFree > _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 128 { //outside the range of data owned by VMS's malloc, so do nothing | |
| 129 return; | |
| 130 } | |
| 131 //subtract size of prolog to get pointer to prolog, then cast | |
| 132 elemToFree = (MallocProlog *)((char *)ptrToFree - sizeof(MallocProlog)); | |
| 133 sizeOfElem =(int32)((char*)elemToFree->nextHigherInMem-(char*)elemToFree); | |
| 134 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem; | |
| 135 | |
| 136 nextLowerElem = elemToFree->nextLowerInMem; | |
| 137 nextHigherElem = elemToFree->nextHigherInMem; | |
| 138 | |
| 139 if( nextHigherElem == NULL ) | |
| 140 higherExistsAndIsFree = FALSE; | |
| 141 else //okay exists, now check if in the free-list by checking back ptr | |
| 142 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL); | |
| 143 | |
| 144 if( nextLowerElem == NULL ) | |
| 145 lowerExistsAndIsFree = FALSE; | |
| 146 else //okay, it exists, now check if it's free | |
| 147 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL); | |
| 148 | |
| 149 | |
| 150 //now, know what exists and what's free | |
| 151 if( lowerExistsAndIsFree ) | |
| 152 { if( higherExistsAndIsFree ) | |
| 153 { //both exist and are free, so coalesce all three | |
| 154 //First, remove higher from free-list | |
| 155 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList = | |
| 156 nextHigherElem->nextChunkInFreeList; | |
| 157 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list? | |
| 158 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 159 nextHigherElem->prevChunkInFreeList; | |
| 160 //Now, fix-up sequence-in-mem list -- by side-effect, this also | |
| 161 // changes size of the lower elem, which is still in free-list | |
| 162 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem; | |
| 163 if( nextHigherElem->nextHigherInMem != | |
| 164 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 165 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem; | |
| 166 //notice didn't do anything to elemToFree -- it simply is no | |
| 167 // longer reachable from any of the lists. Wonder if could be a | |
| 168 // security leak because left valid addresses in it, | |
| 169 // but don't care for now. | |
| 170 } | |
| 171 else | |
| 172 { //lower is the only of the two that exists and is free, | |
| 173 //In this case, no adjustment to free-list, just change mem-list. | |
| 174 // By side-effect, changes size of the lower elem | |
| 175 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem; | |
| 176 if( elemToFree->nextHigherInMem != | |
| 177 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 178 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem; | |
| 179 } | |
| 180 } | |
| 181 else | |
| 182 { //lower either doesn't exist or isn't free, so check higher | |
| 183 if( higherExistsAndIsFree ) | |
| 184 { //higher exists and is the only of the two free | |
| 185 //First, in free-list, replace higher elem with the one to free | |
| 186 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList; | |
| 187 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList; | |
| 188 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree; | |
| 189 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? | |
| 190 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; | |
| 191 //Now chg mem-list. By side-effect, changes size of elemToFree | |
| 192 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem; | |
| 193 if( elemToFree->nextHigherInMem != | |
| 194 _VMSMasterEnv->freeListHead->nextHigherInMem ) | |
| 195 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree; | |
| 196 } | |
| 197 else | |
| 198 { //neither lower nor higher is availabe to coalesce so add to list | |
| 199 // this makes prev chunk ptr non-null, which indicates it's free | |
| 200 elemToFree->nextChunkInFreeList = | |
| 201 _VMSMasterEnv->freeListHead->nextChunkInFreeList; | |
| 202 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree; | |
| 203 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? | |
| 204 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; | |
| 205 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 } | |
| 210 | |
| 211 | |
| 212 /*Designed to be called from the main thread outside of VMS, during init | |
| 213 */ | |
| 214 MallocProlog * | |
| 215 VMS__create_free_list() | |
| 216 { MallocProlog *freeListHead, *firstChunk; | |
| 217 | |
| 218 //Note, this is running in the main thread -- all increases in malloc | |
| 219 // mem and all frees of it must be done in this thread, with the | |
| 220 // thread's original stack available | |
| 221 freeListHead = malloc( sizeof(MallocProlog) ); | |
| 222 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); | |
| 223 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);} | |
| 224 | |
| 225 freeListHead->prevChunkInFreeList = NULL; | |
| 226 //Use this addr to free the heap when cleanup | |
| 227 freeListHead->nextLowerInMem = firstChunk; | |
| 228 //to identify top-of-heap elem, compare this addr to elem's next higher | |
| 229 freeListHead->nextHigherInMem = (char *)firstChunk + | |
| 230 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE; | |
| 231 freeListHead->nextChunkInFreeList = firstChunk; | |
| 232 | |
| 233 firstChunk->nextChunkInFreeList = NULL; | |
| 234 firstChunk->prevChunkInFreeList = freeListHead; | |
| 235 //next Higher has to be set to top of chunk, so can calc size in malloc | |
| 236 firstChunk->nextHigherInMem = (char *)firstChunk + | |
| 237 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE; | |
| 238 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap | |
| 239 | |
| 240 return freeListHead; | |
| 241 } | |
| 242 | |
| 243 | |
| 244 /*Designed to be called from the main thread outside of VMS, during cleanup | |
| 245 */ | |
| 246 void | |
| 247 VMS_ext__free_free_list( MallocProlog *freeListHead ) | |
| 248 { | |
| 249 //stashed a ptr to the one and only bug chunk malloc'd from OS in the | |
| 250 // free list head's next lower in mem pointer | |
| 251 free( freeListHead->nextLowerInMem ); | |
| 252 | |
| 253 //don't free the head -- it'll be in an array eventually -- free whole | |
| 254 // array when all the free lists linked from it have already been freed | |
| 255 } | |
| 256 |
