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