seanhalle@208: /* seanhalle@208: * Copyright 2009 OpenSourceCodeStewardshipFoundation.org seanhalle@208: * Licensed under GNU General Public License version 2 seanhalle@208: * seanhalle@208: * Author: seanhalle@yahoo.com seanhalle@208: * seanhalle@208: * Created on November 14, 2009, 9:07 PM seanhalle@208: */ seanhalle@208: seanhalle@208: #include seanhalle@208: #include seanhalle@208: #include seanhalle@208: #include seanhalle@208: seanhalle@208: #include "VMS.h" seanhalle@208: #include "C_Libraries/Histogram/Histogram.h" seanhalle@208: seanhalle@208: /*Helper function seanhalle@208: *Insert a newly generated free chunk into the first spot on the free list. seanhalle@208: * The chunk is cast as a MallocProlog, so the various pointers in it are seanhalle@208: * accessed with C's help -- and the size of the prolog is easily added to seanhalle@208: * the pointer when a chunk is returned to the app -- so C handles changes seanhalle@208: * in pointer sizes among machines. seanhalle@208: * seanhalle@208: *The list head is a normal MallocProlog struct -- identified by its seanhalle@208: * prevChunkInFreeList being NULL -- the only one. seanhalle@208: * seanhalle@208: *The end of the list is identified by next chunk being NULL, as usual. seanhalle@208: */ seanhalle@208: void inline seanhalle@208: add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead ) seanhalle@208: { seanhalle@208: chunk->nextChunkInFreeList = listHead->nextChunkInFreeList; seanhalle@208: if( chunk->nextChunkInFreeList != NULL ) //if not last in free list seanhalle@208: chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; seanhalle@208: chunk->prevChunkInFreeList = listHead; seanhalle@208: listHead->nextChunkInFreeList = chunk; seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*This is sequential code, meant to only be called from the Master, not from seanhalle@208: * any slave VPs. seanhalle@208: *Search down list, checking size by the nextHigherInMem pointer, to find seanhalle@208: * first chunk bigger than size needed. seanhalle@208: *Shave off the extra and make it into a new free-list element, hook it in seanhalle@208: * then return the address of the found element plus size of prolog. seanhalle@208: * seanhalle@208: */ seanhalle@208: void *VMS_int__malloc( size_t sizeRequested ) seanhalle@208: { MallocProlog *foundElem = NULL, *currElem, *newElem; seanhalle@208: ssize_t amountExtra, sizeConsumed,sizeOfFound; seanhalle@208: uint32 foundElemIsTopOfHeap; seanhalle@208: seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: int32 startStamp, endStamp; seanhalle@208: saveLowTimeStampCountInto( startStamp ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: //step up the size to be aligned at 16-byte boundary, prob better ways seanhalle@208: sizeRequested = (sizeRequested + 16) & ~15; seanhalle@208: currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; seanhalle@208: seanhalle@208: while( currElem != NULL ) seanhalle@208: { //check if size of currElem is big enough seanhalle@208: sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); seanhalle@208: amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); seanhalle@208: if( amountExtra > 0 ) seanhalle@208: { //found it, get out of loop seanhalle@208: foundElem = currElem; seanhalle@208: currElem = NULL; seanhalle@208: } seanhalle@208: else seanhalle@208: currElem = currElem->nextChunkInFreeList; seanhalle@208: } seanhalle@208: seanhalle@208: if( foundElem == NULL ) seanhalle@208: { ERROR("\nmalloc failed\n") seanhalle@208: return (void *)NULL; //indicates malloc failed seanhalle@208: } seanhalle@208: //Using a kludge to identify the element that is the top chunk in the seanhalle@208: // heap -- saving top-of-heap addr in head's nextHigherInMem -- and seanhalle@208: // save addr of start of heap in head's nextLowerInMem seanhalle@208: //Will handle top of Heap specially seanhalle@208: foundElemIsTopOfHeap = foundElem->nextHigherInMem == seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem; seanhalle@208: seanhalle@208: //before shave off and try to insert new elem, remove found elem seanhalle@208: //note, foundElem will never be the head, so always has valid prevChunk seanhalle@208: foundElem->prevChunkInFreeList->nextChunkInFreeList = seanhalle@208: foundElem->nextChunkInFreeList; seanhalle@208: if( foundElem->nextChunkInFreeList != NULL ) seanhalle@208: { foundElem->nextChunkInFreeList->prevChunkInFreeList = seanhalle@208: foundElem->prevChunkInFreeList; seanhalle@208: } seanhalle@208: foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated seanhalle@208: seanhalle@208: //if enough, turn extra into new elem & insert it seanhalle@208: if( amountExtra > 64 ) seanhalle@208: { //make new elem by adding to addr of curr elem then casting seanhalle@208: sizeConsumed = sizeof(MallocProlog) + sizeRequested; seanhalle@208: newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); seanhalle@208: newElem->nextLowerInMem = foundElem; //This is evil (but why?) seanhalle@208: newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?) seanhalle@208: foundElem->nextHigherInMem = newElem; seanhalle@208: if( ! foundElemIsTopOfHeap ) seanhalle@208: { //there is no next higher for top of heap, so can't write to it seanhalle@208: newElem->nextHigherInMem->nextLowerInMem = newElem; seanhalle@208: } seanhalle@208: add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); seanhalle@208: } seanhalle@208: else seanhalle@208: { seanhalle@208: sizeConsumed = sizeOfFound; seanhalle@208: } seanhalle@208: _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; seanhalle@208: seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: saveLowTimeStampCountInto( endStamp ); seanhalle@208: addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: //skip over the prolog by adding its size to the pointer return seanhalle@208: return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); seanhalle@208: } seanhalle@208: seanhalle@208: /*This is sequential code, meant to only be called from the Master, not from seanhalle@208: * any slave VPs. seanhalle@208: *Search down list, checking size by the nextHigherInMem pointer, to find seanhalle@208: * first chunk bigger than size needed. seanhalle@208: *Shave off the extra and make it into a new free-list element, hook it in seanhalle@208: * then return the address of the found element plus size of prolog. seanhalle@208: * seanhalle@208: * The difference to the regular malloc is, that all the allocated chunks are seanhalle@208: * aligned and padded to the size of a CACHE_LINE_SZ. Thus creating a new chunk seanhalle@208: * before the aligned chunk. seanhalle@208: */ seanhalle@208: void *VMS_int__malloc_aligned( size_t sizeRequested ) seanhalle@208: { MallocProlog *foundElem = NULL, *currElem, *newElem; seanhalle@208: ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount; seanhalle@208: uint32 foundElemIsTopOfHeap; seanhalle@208: seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: uint32 startStamp, endStamp; seanhalle@208: saveLowTimeStampCountInto( startStamp ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: //step up the size to be multiple of the cache line size seanhalle@208: sizeRequested = (sizeRequested + CACHE_LINE_SZ) & ~(CACHE_LINE_SZ-1); seanhalle@208: currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; seanhalle@208: seanhalle@208: while( currElem != NULL ) seanhalle@208: { //check if size of currElem is big enough seanhalle@208: sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); seanhalle@208: amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); seanhalle@208: if( amountExtra > 0 ) seanhalle@208: { seanhalle@208: //look if the found element is already aligned seanhalle@208: if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE_SZ-1)) == 0){ seanhalle@208: //found it, get out of loop seanhalle@208: foundElem = currElem; seanhalle@208: break; seanhalle@208: }else{ seanhalle@208: //find first aligned address and check if it's still big enough seanhalle@208: //check also if the space before the aligned address is big enough seanhalle@208: //for a new element seanhalle@208: void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE_SZ) & ~((uintptr_t)(CACHE_LINE_SZ-1))); seanhalle@208: prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem; seanhalle@208: sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog); seanhalle@208: amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog); seanhalle@208: if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){ seanhalle@208: //found suitable element seanhalle@208: //create new previous element and exit loop seanhalle@208: MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1; seanhalle@208: seanhalle@208: //insert new element into free list seanhalle@208: if(currElem->nextChunkInFreeList != NULL) seanhalle@208: currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem; seanhalle@208: newAlignedElem->prevChunkInFreeList = currElem; seanhalle@208: newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList; seanhalle@208: currElem->nextChunkInFreeList = newAlignedElem; seanhalle@208: seanhalle@208: //set higherInMem and lowerInMem seanhalle@208: newAlignedElem->nextHigherInMem = currElem->nextHigherInMem; seanhalle@208: foundElemIsTopOfHeap = currElem->nextHigherInMem == seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem; seanhalle@208: if(!foundElemIsTopOfHeap) seanhalle@208: currElem->nextHigherInMem->nextLowerInMem = newAlignedElem; seanhalle@208: currElem->nextHigherInMem = newAlignedElem; seanhalle@208: newAlignedElem->nextLowerInMem = currElem; seanhalle@208: seanhalle@208: //Found new element leaving loop seanhalle@208: foundElem = newAlignedElem; seanhalle@208: break; seanhalle@208: } seanhalle@208: } seanhalle@208: seanhalle@208: } seanhalle@208: currElem = currElem->nextChunkInFreeList; seanhalle@208: } seanhalle@208: seanhalle@208: if( foundElem == NULL ) seanhalle@208: { ERROR("\nmalloc failed\n") seanhalle@208: return (void *)NULL; //indicates malloc failed seanhalle@208: } seanhalle@208: //Using a kludge to identify the element that is the top chunk in the seanhalle@208: // heap -- saving top-of-heap addr in head's nextHigherInMem -- and seanhalle@208: // save addr of start of heap in head's nextLowerInMem seanhalle@208: //Will handle top of Heap specially seanhalle@208: foundElemIsTopOfHeap = foundElem->nextHigherInMem == seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem; seanhalle@208: seanhalle@208: //before shave off and try to insert new elem, remove found elem seanhalle@208: //note, foundElem will never be the head, so always has valid prevChunk seanhalle@208: foundElem->prevChunkInFreeList->nextChunkInFreeList = seanhalle@208: foundElem->nextChunkInFreeList; seanhalle@208: if( foundElem->nextChunkInFreeList != NULL ) seanhalle@208: { foundElem->nextChunkInFreeList->prevChunkInFreeList = seanhalle@208: foundElem->prevChunkInFreeList; seanhalle@208: } seanhalle@208: foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated seanhalle@208: seanhalle@208: //if enough, turn extra into new elem & insert it seanhalle@208: if( amountExtra > 64 ) seanhalle@208: { //make new elem by adding to addr of curr elem then casting seanhalle@208: sizeConsumed = sizeof(MallocProlog) + sizeRequested; seanhalle@208: newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); seanhalle@208: newElem->nextHigherInMem = foundElem->nextHigherInMem; seanhalle@208: newElem->nextLowerInMem = foundElem; seanhalle@208: foundElem->nextHigherInMem = newElem; seanhalle@208: seanhalle@208: if( ! foundElemIsTopOfHeap ) seanhalle@208: { //there is no next higher for top of heap, so can't write to it seanhalle@208: newElem->nextHigherInMem->nextLowerInMem = newElem; seanhalle@208: } seanhalle@208: add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); seanhalle@208: } seanhalle@208: else seanhalle@208: { seanhalle@208: sizeConsumed = sizeOfFound; seanhalle@208: } seanhalle@208: _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; seanhalle@208: seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: saveLowTimeStampCountInto( endStamp ); seanhalle@208: addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: //skip over the prolog by adding its size to the pointer return seanhalle@208: return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*This is sequential code -- only to be called from the Master seanhalle@208: * When free, subtract the size of prolog from pointer, then cast it to a seanhalle@208: * MallocProlog. Then check the nextLower and nextHigher chunks to see if seanhalle@208: * one or both are also free, and coalesce if so, and if neither free, then seanhalle@208: * add this one to free-list. seanhalle@208: */ seanhalle@208: void seanhalle@208: VMS_int__free( void *ptrToFree ) seanhalle@208: { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; seanhalle@208: size_t sizeOfElem; seanhalle@208: uint32 lowerExistsAndIsFree, higherExistsAndIsFree; seanhalle@208: seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: int32 startStamp, endStamp; seanhalle@208: saveLowTimeStampCountInto( startStamp ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem || seanhalle@208: ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem ) seanhalle@208: { //outside the range of data owned by VMS's malloc, so do nothing seanhalle@208: return; seanhalle@208: } seanhalle@208: //subtract size of prolog to get pointer to prolog, then cast seanhalle@208: elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog)); seanhalle@208: sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree); seanhalle@208: seanhalle@208: if( elemToFree->prevChunkInFreeList != NULL ) seanhalle@208: { printf( "error: freeing same element twice!" ); exit(1); seanhalle@208: } seanhalle@208: seanhalle@208: _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem; seanhalle@208: seanhalle@208: nextLowerElem = elemToFree->nextLowerInMem; seanhalle@208: nextHigherElem = elemToFree->nextHigherInMem; seanhalle@208: seanhalle@208: if( nextHigherElem == NULL ) seanhalle@208: higherExistsAndIsFree = FALSE; seanhalle@208: else //okay exists, now check if in the free-list by checking back ptr seanhalle@208: higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL); seanhalle@208: seanhalle@208: if( nextLowerElem == NULL ) seanhalle@208: lowerExistsAndIsFree = FALSE; seanhalle@208: else //okay, it exists, now check if it's free seanhalle@208: lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL); seanhalle@208: seanhalle@208: seanhalle@208: //now, know what exists and what's free seanhalle@208: if( lowerExistsAndIsFree ) seanhalle@208: { if( higherExistsAndIsFree ) seanhalle@208: { //both exist and are free, so coalesce all three seanhalle@208: //First, remove higher from free-list seanhalle@208: nextHigherElem->prevChunkInFreeList->nextChunkInFreeList = seanhalle@208: nextHigherElem->nextChunkInFreeList; seanhalle@208: if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list? seanhalle@208: nextHigherElem->nextChunkInFreeList->prevChunkInFreeList = seanhalle@208: nextHigherElem->prevChunkInFreeList; seanhalle@208: //Now, fix-up sequence-in-mem list -- by side-effect, this also seanhalle@208: // changes size of the lower elem, which is still in free-list seanhalle@208: nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem; seanhalle@208: if( nextHigherElem->nextHigherInMem != seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem ) seanhalle@208: nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem; seanhalle@208: //notice didn't do anything to elemToFree -- it simply is no seanhalle@208: // longer reachable from any of the lists. Wonder if could be a seanhalle@208: // security leak because left valid addresses in it, seanhalle@208: // but don't care for now. seanhalle@208: } seanhalle@208: else seanhalle@208: { //lower is the only of the two that exists and is free, seanhalle@208: //In this case, no adjustment to free-list, just change mem-list. seanhalle@208: // By side-effect, changes size of the lower elem seanhalle@208: nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem; seanhalle@208: if( elemToFree->nextHigherInMem != seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem ) seanhalle@208: elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem; seanhalle@208: } seanhalle@208: } seanhalle@208: else seanhalle@208: { //lower either doesn't exist or isn't free, so check higher seanhalle@208: if( higherExistsAndIsFree ) seanhalle@208: { //higher exists and is the only of the two free seanhalle@208: //First, in free-list, replace higher elem with the one to free seanhalle@208: elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList; seanhalle@208: elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList; seanhalle@208: elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree; seanhalle@208: if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? seanhalle@208: elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; seanhalle@208: //Now chg mem-list. By side-effect, changes size of elemToFree seanhalle@208: elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem; seanhalle@208: if( elemToFree->nextHigherInMem != seanhalle@208: _VMSMasterEnv->freeListHead->nextHigherInMem ) seanhalle@208: elemToFree->nextHigherInMem->nextLowerInMem = elemToFree; seanhalle@208: } seanhalle@208: else seanhalle@208: { //neither lower nor higher is availabe to coalesce so add to list seanhalle@208: // this makes prev chunk ptr non-null, which indicates it's free seanhalle@208: elemToFree->nextChunkInFreeList = seanhalle@208: _VMSMasterEnv->freeListHead->nextChunkInFreeList; seanhalle@208: _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree; seanhalle@208: if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list? seanhalle@208: elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree; seanhalle@208: elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead; seanhalle@208: } seanhalle@208: } seanhalle@208: //============================= MEASUREMENT STUFF ======================== seanhalle@208: #ifdef MEAS__TIME_MALLOC seanhalle@208: saveLowTimeStampCountInto( endStamp ); seanhalle@208: addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist ); seanhalle@208: #endif seanhalle@208: //======================================================================== seanhalle@208: seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*Allocates memory from the external system -- higher overhead seanhalle@208: * seanhalle@208: *Because of Linux's malloc throwing bizarre random faults when malloc is seanhalle@208: * used inside a VMS virtual processor, have to pass this as a request and seanhalle@208: * have the core loop do it when it gets around to it -- will look for these seanhalle@208: * chores leftover from the previous animation of masterVP the next time it seanhalle@208: * goes to animate the masterVP -- so it takes two separate masterVP seanhalle@208: * animations, separated by work, to complete an external malloc or seanhalle@208: * external free request. seanhalle@208: * seanhalle@208: *Thinking core loop accepts signals -- just looks if signal-location is seanhalle@208: * empty or not -- seanhalle@208: */ seanhalle@208: void * seanhalle@208: VMS__malloc_in_ext( size_t sizeRequested ) seanhalle@208: { seanhalle@208: /* seanhalle@208: //This is running in the master, so no chance for multiple cores to be seanhalle@208: // competing for the core's flag. seanhalle@208: if( *(_VMSMasterEnv->coreLoopSignalAddr[ 0 ]) != 0 ) seanhalle@208: { //something has already signalled to core loop, so save the signal seanhalle@208: // and look, next time master animated, to see if can send it. seanhalle@208: //Note, the addr to put a signal is in the coreloop's frame, so just seanhalle@208: // checks it each time through -- make it volatile to avoid GCC seanhalle@208: // optimizations -- it's a coreloop local var that only changes seanhalle@208: // after jumping away. The signal includes the addr to send the seanhalle@208: //return to -- even if just empty return completion-signal seanhalle@208: // seanhalle@208: //save the signal in some queue that the master looks at each time seanhalle@208: // it starts up -- one loc says if empty for fast common case -- seanhalle@208: //something like that -- want to hide this inside this call -- but seanhalle@208: // think this has to come as a request -- req handler gives procr seanhalle@208: // back to master loop, which gives it back to req handler at point seanhalle@208: // it sees that core loop has sent return signal. Something like seanhalle@208: // that. seanhalle@208: saveTheSignal seanhalle@208: seanhalle@208: } seanhalle@208: coreSigData->type = malloc; seanhalle@208: coreSigData->sizeToMalloc = sizeRequested; seanhalle@208: coreSigData->locToSignalCompletion = &figureOut; seanhalle@208: _VMSMasterEnv->coreLoopSignals[ 0 ] = coreSigData; seanhalle@208: */ seanhalle@208: //just risk system-stack faults until get this figured out seanhalle@208: return malloc( sizeRequested ); seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*Frees memory that was allocated in the external system -- higher overhead seanhalle@208: * seanhalle@208: *As noted in external malloc comment, this is clunky 'cause the free has seanhalle@208: * to be called in the core loop. seanhalle@208: */ seanhalle@208: void seanhalle@208: VMS__free_in_ext( void *ptrToFree ) seanhalle@208: { seanhalle@208: //just risk system-stack faults until get this figured out seanhalle@208: free( ptrToFree ); seanhalle@208: seanhalle@208: //TODO: fix this -- so seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*Designed to be called from the main thread outside of VMS, during init seanhalle@208: */ seanhalle@208: MallocProlog * seanhalle@208: VMS_ext__create_free_list() seanhalle@208: { MallocProlog *freeListHead, *firstChunk; seanhalle@208: seanhalle@208: //Note, this is running in the main thread -- all increases in malloc seanhalle@208: // mem and all frees of it must be done in this thread, with the seanhalle@208: // thread's original stack available seanhalle@208: freeListHead = malloc( sizeof(MallocProlog) ); seanhalle@208: firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); seanhalle@208: if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);} seanhalle@208: seanhalle@208: //Touch memory to avoid page faults seanhalle@208: void *ptr,*endPtr; seanhalle@208: endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE; seanhalle@208: for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE) seanhalle@208: { seanhalle@208: *(char*)ptr = 0; seanhalle@208: } seanhalle@208: seanhalle@208: freeListHead->prevChunkInFreeList = NULL; seanhalle@208: //Use this addr to free the heap when cleanup seanhalle@208: freeListHead->nextLowerInMem = firstChunk; seanhalle@208: //to identify top-of-heap elem, compare this addr to elem's next higher seanhalle@208: freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk + seanhalle@208: MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE); seanhalle@208: freeListHead->nextChunkInFreeList = firstChunk; seanhalle@208: seanhalle@208: firstChunk->nextChunkInFreeList = NULL; seanhalle@208: firstChunk->prevChunkInFreeList = freeListHead; seanhalle@208: //next Higher has to be set to top of chunk, so can calc size in malloc seanhalle@208: firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk + seanhalle@208: MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE); seanhalle@208: firstChunk->nextLowerInMem = NULL; //identifies as bott of heap seanhalle@208: seanhalle@208: _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet seanhalle@208: seanhalle@208: return freeListHead; seanhalle@208: } seanhalle@208: seanhalle@208: seanhalle@208: /*Designed to be called from the main thread outside of VMS, during cleanup seanhalle@208: */ seanhalle@208: void seanhalle@208: VMS_ext__free_free_list( MallocProlog *freeListHead ) seanhalle@208: { seanhalle@208: //stashed a ptr to the one and only bug chunk malloc'd from OS in the seanhalle@208: // free list head's next lower in mem pointer seanhalle@208: free( freeListHead->nextLowerInMem ); seanhalle@208: seanhalle@208: //don't free the head -- it'll be in an array eventually -- free whole seanhalle@208: // array when all the free lists linked from it have already been freed seanhalle@208: } seanhalle@208: