annotate vmalloc.c @ 137:99343ffe1918

The shutdown now uses inter master requests
author Merten Sach <msach@mailbox.tu-berlin.de>
date Mon, 19 Sep 2011 14:15:37 +0200
parents 0b49fd35afc1
children 99798e4438a6
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>
msach@76 11 #include <inttypes.h>
Me@53 12 #include <stdlib.h>
msach@76 13 #include <stdio.h>
Me@50 14
msach@134 15 #include "VMS.h"
Me@68 16 #include "Histogram/Histogram.h"
Me@50 17
msach@135 18 inline void
msach@135 19 sendFreeReqst_lib(int receiverID, void *ptrToFree, VirtProcr *animPr);
msach@135 20
msach@135 21 inline void
msach@135 22 sendFreeReqst_master(int receiverID, void *ptrToFree);
msach@135 23
Me@50 24 /*Helper function
Me@50 25 *Insert a newly generated free chunk into the first spot on the free list.
Me@50 26 * The chunk is cast as a MallocProlog, so the various pointers in it are
Me@50 27 * accessed with C's help -- and the size of the prolog is easily added to
Me@50 28 * the pointer when a chunk is returned to the app -- so C handles changes
Me@50 29 * in pointer sizes among machines.
Me@50 30 *
Me@50 31 *The list head is a normal MallocProlog struct -- identified by its
Me@50 32 * prevChunkInFreeList being NULL -- the only one.
Me@50 33 *
Me@50 34 *The end of the list is identified by next chunk being NULL, as usual.
Me@50 35 */
Me@50 36 void inline
Me@50 37 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
Me@50 38 {
Me@50 39 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList;
Me@50 40 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
Me@50 41 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
Me@50 42 chunk->prevChunkInFreeList = listHead;
Me@50 43 listHead->nextChunkInFreeList = chunk;
Me@50 44 }
Me@50 45
msach@132 46 /*
msach@132 47 * This function is called by code which is part of the master loop.
msach@132 48 * This reads the animating coreID from the MasterEnv and calls the normal malloc
msach@132 49 * in VMS__malloc_on_core
msach@132 50 */
msach@132 51 void *
msach@132 52 VMS__malloc( size_t sizeRequested)
msach@132 53 {
msach@132 54 return VMS__malloc_on_core(sizeRequested, _VMSMasterEnv->currentMasterProcrID);
msach@132 55 }
Me@50 56
msach@132 57 /*
msach@132 58 * This is called by the plugin. This call to VMS_malloc_on_core is run on the
msach@132 59 * slave VPs stack so there is no switch to the VMS runtime.
msach@132 60 */
msach@132 61 void *
msach@132 62 VMS__malloc_in_lib(size_t sizeRequested, VirtProcr *VProcr)
msach@132 63 {
msach@132 64 return VMS__malloc_on_core(sizeRequested, VProcr->coreAnimatedBy);
msach@132 65 }
msach@132 66
msach@132 67 /*
Me@50 68 *Search down list, checking size by the nextHigherInMem pointer, to find
Me@50 69 * first chunk bigger than size needed.
Me@50 70 *Shave off the extra and make it into a new free-list element, hook it in
Me@50 71 * then return the address of the found element plus size of prolog.
Me@50 72 */
msach@132 73 void *
msach@132 74 VMS__malloc_on_core( size_t sizeRequested, int procrID)
Me@50 75 { MallocProlog *foundElem = NULL, *currElem, *newElem;
msach@132 76 MallocPrologAllocated *returnElem;
msach@76 77 ssize_t amountExtra, sizeConsumed,sizeOfFound;
msach@76 78 uint32 foundElemIsTopOfHeap;
Me@50 79
Me@65 80 //============================= MEASUREMENT STUFF ========================
Me@65 81 #ifdef MEAS__TIME_MALLOC
Me@65 82 int32 startStamp, endStamp;
Me@65 83 saveLowTimeStampCountInto( startStamp );
Me@65 84 #endif
Me@65 85 //========================================================================
Me@65 86
Me@50 87 //step up the size to be aligned at 16-byte boundary, prob better ways
msach@78 88 sizeRequested = (sizeRequested + 16) & ~15;
msach@134 89 currElem = (_VMSMasterEnv->freeListHead[procrID])
msach@132 90 ->nextChunkInFreeList;
Me@50 91
Me@50 92 while( currElem != NULL )
Me@50 93 { //check if size of currElem is big enough
msach@76 94 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
Me@50 95 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
Me@50 96 if( amountExtra > 0 )
Me@50 97 { //found it, get out of loop
Me@50 98 foundElem = currElem;
Me@50 99 currElem = NULL;
Me@50 100 }
Me@50 101 else
Me@50 102 currElem = currElem->nextChunkInFreeList;
Me@50 103 }
msach@78 104
msach@78 105 if( foundElem == NULL )
msach@137 106 { ERROR1("\nMalloc failed, requested size: %d\n", sizeRequested);
msach@78 107 return (void *)NULL; //indicates malloc failed
msach@78 108 }
msach@78 109 //Using a kludge to identify the element that is the top chunk in the
msach@78 110 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
msach@78 111 // save addr of start of heap in head's nextLowerInMem
msach@78 112 //Will handle top of Heap specially
msach@78 113 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
msach@134 114 _VMSMasterEnv->freeListHead[procrID]->nextHigherInMem;
msach@78 115
msach@78 116 //before shave off and try to insert new elem, remove found elem
msach@78 117 //note, foundElem will never be the head, so always has valid prevChunk
msach@78 118 foundElem->prevChunkInFreeList->nextChunkInFreeList =
msach@78 119 foundElem->nextChunkInFreeList;
msach@78 120 if( foundElem->nextChunkInFreeList != NULL )
msach@78 121 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
msach@78 122 foundElem->prevChunkInFreeList;
msach@78 123 }
msach@132 124 returnElem = (MallocPrologAllocated*)foundElem;
msach@132 125 returnElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
msach@132 126 returnElem->procrID = procrID;
msach@78 127
msach@78 128 //if enough, turn extra into new elem & insert it
msach@78 129 if( amountExtra > 64 )
msach@78 130 { //make new elem by adding to addr of curr elem then casting
msach@78 131 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
msach@132 132 newElem = (MallocProlog *)( (uintptr_t)returnElem + sizeConsumed );
msach@134 133 newElem->nextLowerInMem = (MallocProlog*)returnElem;
msach@134 134 newElem->nextHigherInMem = returnElem->nextHigherInMem;
msach@132 135 returnElem->nextHigherInMem = newElem;
msach@78 136 if( ! foundElemIsTopOfHeap )
msach@78 137 { //there is no next higher for top of heap, so can't write to it
msach@78 138 newElem->nextHigherInMem->nextLowerInMem = newElem;
msach@78 139 }
msach@134 140 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead[procrID] );
msach@78 141 }
msach@78 142 else
msach@78 143 {
msach@78 144 sizeConsumed = sizeOfFound;
msach@78 145 }
msach@78 146 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
msach@78 147
msach@78 148 //============================= MEASUREMENT STUFF ========================
msach@78 149 #ifdef MEAS__TIME_MALLOC
msach@78 150 saveLowTimeStampCountInto( endStamp );
msach@78 151 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
msach@78 152 #endif
msach@78 153 //========================================================================
msach@78 154
msach@78 155 //skip over the prolog by adding its size to the pointer return
msach@132 156 return (void*)((uintptr_t)returnElem + sizeof(MallocProlog));
msach@78 157 }
msach@78 158
msach@132 159 /*
msach@132 160 * This free is called for a master loop. It decides whether the allocation of
msach@132 161 * chunk was done on the same core. If it was it calls VMS__free_on_core
msach@132 162 * otherwise it sends a message to the responsible core.
msach@78 163 */
msach@132 164 void
msach@132 165 VMS__free(void *ptrToFree)
msach@132 166 {
msach@134 167 MallocPrologAllocated *chunk = (MallocPrologAllocated*)ptrToFree - 1;
msach@132 168 if(chunk->procrID == _VMSMasterEnv->currentMasterProcrID)
msach@132 169 {
msach@132 170 VMS__free_on_core(ptrToFree, _VMSMasterEnv->currentMasterProcrID);
msach@132 171 }
msach@132 172 else
msach@132 173 {
msach@135 174 sendFreeReqst_master(chunk->procrID, ptrToFree);
msach@135 175
msach@132 176 }
msach@132 177 }
msach@78 178
msach@132 179 /*
msach@132 180 * This free is called for the plugins. It decides whether the allocation of
msach@132 181 * chunk was done on the same core. If it was it calls VMS__free_on_core
msach@132 182 * otherwise it sends a message to the responsible core.
msach@132 183 */
msach@132 184 void
msach@132 185 VMS__free_in_lib(void *ptrToFree, VirtProcr *VProc)
msach@132 186 {
msach@134 187 MallocPrologAllocated *chunk = (MallocPrologAllocated*)ptrToFree - 1;
msach@132 188 if(chunk->procrID == VProc->coreAnimatedBy)
msach@132 189 {
msach@132 190 VMS__free_on_core(ptrToFree, VProc->coreAnimatedBy);
msach@78 191 }
msach@132 192 else
msach@132 193 {
msach@135 194 sendFreeReqst_lib(chunk->procrID, ptrToFree, VProc);
Me@50 195 }
msach@132 196 }
Me@50 197
msach@135 198 /*
msach@135 199 * This is called form a masterVP and request an free from a different masterVP.
msach@135 200 * The free of the request structure is done after the request is handled.
msach@135 201 */
msach@135 202 inline void
msach@135 203 sendFreeReqst_master(int receiverID, void *ptrToFree)
msach@135 204 {
msach@135 205 InterVMSCoreReqst *freeReqst = VMS__malloc(sizeof(InterVMSCoreReqst));
msach@135 206 freeReqst->freePtr = ptrToFree;
msach@135 207 freeReqst->secondReqType = transfer_free_ptr;
msach@135 208
msach@135 209 sendInterMasterReqst(receiverID, (InterMasterReqst*)freeReqst);
msach@135 210 }
msach@135 211
msach@135 212 /*
msach@135 213 * This is called if the free is called from the plugin. This requests an inter
msach@135 214 * master request from his master.
msach@135 215 */
msach@135 216 inline void
msach@135 217 sendFreeReqst_lib(int receiverID, void *ptrToFree, VirtProcr *animPr )
msach@135 218 {
msach@135 219 VMSSemReq reqData;
msach@135 220 InterVMSCoreReqst *freeReqst = VMS__malloc(sizeof(InterVMSCoreReqst));
msach@135 221 freeReqst->freePtr = ptrToFree;
msach@135 222 freeReqst->secondReqType = transfer_free_ptr;
msach@135 223
msach@135 224 reqData.reqType = interMasterReqst;
msach@135 225 reqData.receiverID = receiverID;
msach@135 226 reqData.data = (void*)freeReqst;
msach@135 227
msach@135 228 VMS__send_VMSSem_request( (void*)&reqData, animPr );
msach@135 229 }
msach@135 230
Me@50 231 /*This is sequential code -- only to be called from the Master
Me@50 232 * When free, subtract the size of prolog from pointer, then cast it to a
Me@50 233 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
Me@50 234 * one or both are also free, and coalesce if so, and if neither free, then
Me@50 235 * add this one to free-list.
Me@50 236 */
Me@50 237 void
msach@132 238 VMS__free_on_core( void *ptrToFree, int procrID)
Me@50 239 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
msach@76 240 size_t sizeOfElem;
msach@76 241 uint32 lowerExistsAndIsFree, higherExistsAndIsFree;
Me@50 242
Me@65 243 //============================= MEASUREMENT STUFF ========================
Me@65 244 #ifdef MEAS__TIME_MALLOC
Me@65 245 int32 startStamp, endStamp;
Me@65 246 saveLowTimeStampCountInto( startStamp );
Me@65 247 #endif
Me@65 248 //========================================================================
msach@134 249
msach@134 250 MallocProlog* masterListHead = _VMSMasterEnv->freeListHead[procrID];
Me@65 251
msach@134 252 if( ptrToFree < (void*)masterListHead->nextLowerInMem ||
msach@134 253 ptrToFree > (void*)masterListHead->nextHigherInMem )
Me@50 254 { //outside the range of data owned by VMS's malloc, so do nothing
Me@50 255 return;
Me@50 256 }
Me@50 257 //subtract size of prolog to get pointer to prolog, then cast
msach@76 258 elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog));
msach@76 259 sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree);
Me@53 260
Me@53 261 if( elemToFree->prevChunkInFreeList != NULL )
Me@53 262 { printf( "error: freeing same element twice!" ); exit(1);
Me@53 263 }
Me@53 264
Me@50 265 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
Me@50 266
Me@50 267 nextLowerElem = elemToFree->nextLowerInMem;
Me@50 268 nextHigherElem = elemToFree->nextHigherInMem;
Me@50 269
Me@50 270 if( nextHigherElem == NULL )
Me@50 271 higherExistsAndIsFree = FALSE;
Me@50 272 else //okay exists, now check if in the free-list by checking back ptr
Me@50 273 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
Me@50 274
Me@50 275 if( nextLowerElem == NULL )
Me@50 276 lowerExistsAndIsFree = FALSE;
Me@50 277 else //okay, it exists, now check if it's free
Me@50 278 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
Me@50 279
Me@50 280
Me@50 281 //now, know what exists and what's free
Me@50 282 if( lowerExistsAndIsFree )
Me@50 283 { if( higherExistsAndIsFree )
Me@50 284 { //both exist and are free, so coalesce all three
Me@50 285 //First, remove higher from free-list
Me@50 286 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
Me@50 287 nextHigherElem->nextChunkInFreeList;
Me@50 288 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
Me@50 289 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
Me@50 290 nextHigherElem->prevChunkInFreeList;
Me@50 291 //Now, fix-up sequence-in-mem list -- by side-effect, this also
Me@50 292 // changes size of the lower elem, which is still in free-list
Me@50 293 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
Me@50 294 if( nextHigherElem->nextHigherInMem !=
msach@134 295 masterListHead->nextHigherInMem )
Me@50 296 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
Me@50 297 //notice didn't do anything to elemToFree -- it simply is no
Me@50 298 // longer reachable from any of the lists. Wonder if could be a
Me@50 299 // security leak because left valid addresses in it,
Me@50 300 // but don't care for now.
Me@50 301 }
Me@50 302 else
Me@50 303 { //lower is the only of the two that exists and is free,
Me@50 304 //In this case, no adjustment to free-list, just change mem-list.
Me@50 305 // By side-effect, changes size of the lower elem
Me@50 306 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
Me@50 307 if( elemToFree->nextHigherInMem !=
msach@134 308 masterListHead->nextHigherInMem )
Me@50 309 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
Me@50 310 }
Me@50 311 }
Me@50 312 else
Me@50 313 { //lower either doesn't exist or isn't free, so check higher
Me@50 314 if( higherExistsAndIsFree )
Me@50 315 { //higher exists and is the only of the two free
Me@50 316 //First, in free-list, replace higher elem with the one to free
Me@50 317 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
Me@50 318 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
Me@50 319 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
Me@50 320 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
Me@50 321 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
Me@50 322 //Now chg mem-list. By side-effect, changes size of elemToFree
Me@50 323 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
Me@50 324 if( elemToFree->nextHigherInMem !=
msach@134 325 masterListHead->nextHigherInMem )
Me@50 326 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
Me@50 327 }
Me@50 328 else
Me@50 329 { //neither lower nor higher is availabe to coalesce so add to list
Me@50 330 // this makes prev chunk ptr non-null, which indicates it's free
Me@50 331 elemToFree->nextChunkInFreeList =
msach@134 332 masterListHead->nextChunkInFreeList;
msach@134 333 masterListHead->nextChunkInFreeList = elemToFree;
Me@50 334 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
Me@50 335 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
msach@134 336 elemToFree->prevChunkInFreeList = masterListHead;
Me@50 337 }
Me@50 338 }
Me@65 339 //============================= MEASUREMENT STUFF ========================
Me@65 340 #ifdef MEAS__TIME_MALLOC
Me@65 341 saveLowTimeStampCountInto( endStamp );
Me@65 342 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist );
Me@65 343 #endif
Me@65 344 //========================================================================
Me@50 345
Me@50 346 }
Me@50 347
Me@50 348
Me@53 349 /*Allocates memory from the external system -- higher overhead
Me@53 350 *
Me@53 351 *Because of Linux's malloc throwing bizarre random faults when malloc is
Me@53 352 * used inside a VMS virtual processor, have to pass this as a request and
Me@53 353 * have the core loop do it when it gets around to it -- will look for these
Me@53 354 * chores leftover from the previous animation of masterVP the next time it
Me@53 355 * goes to animate the masterVP -- so it takes two separate masterVP
Me@53 356 * animations, separated by work, to complete an external malloc or
Me@53 357 * external free request.
Me@53 358 *
Me@53 359 *Thinking core loop accepts signals -- just looks if signal-location is
Me@53 360 * empty or not --
Me@53 361 */
Me@53 362 void *
msach@76 363 VMS__malloc_in_ext( size_t sizeRequested )
Me@53 364 {
Me@53 365 /*
Me@53 366 //This is running in the master, so no chance for multiple cores to be
Me@53 367 // competing for the core's flag.
Me@53 368 if( *(_VMSMasterEnv->coreLoopSignalAddr[ 0 ]) != 0 )
Me@53 369 { //something has already signalled to core loop, so save the signal
Me@53 370 // and look, next time master animated, to see if can send it.
Me@53 371 //Note, the addr to put a signal is in the coreloop's frame, so just
Me@53 372 // checks it each time through -- make it volatile to avoid GCC
Me@53 373 // optimizations -- it's a coreloop local var that only changes
Me@53 374 // after jumping away. The signal includes the addr to send the
Me@53 375 //return to -- even if just empty return completion-signal
Me@53 376 //
Me@53 377 //save the signal in some queue that the master looks at each time
Me@53 378 // it starts up -- one loc says if empty for fast common case --
Me@53 379 //something like that -- want to hide this inside this call -- but
Me@53 380 // think this has to come as a request -- req handler gives procr
Me@53 381 // back to master loop, which gives it back to req handler at point
Me@53 382 // it sees that core loop has sent return signal. Something like
Me@53 383 // that.
Me@53 384 saveTheSignal
Me@53 385
Me@53 386 }
Me@53 387 coreSigData->type = malloc;
Me@53 388 coreSigData->sizeToMalloc = sizeRequested;
Me@53 389 coreSigData->locToSignalCompletion = &figureOut;
Me@53 390 _VMSMasterEnv->coreLoopSignals[ 0 ] = coreSigData;
Me@53 391 */
Me@53 392 //just risk system-stack faults until get this figured out
Me@53 393 return malloc( sizeRequested );
Me@53 394 }
Me@53 395
Me@53 396
Me@53 397 /*Frees memory that was allocated in the external system -- higher overhead
Me@53 398 *
Me@53 399 *As noted in external malloc comment, this is clunky 'cause the free has
Me@53 400 * to be called in the core loop.
Me@53 401 */
Me@53 402 void
Me@53 403 VMS__free_in_ext( void *ptrToFree )
Me@53 404 {
Me@53 405 //just risk system-stack faults until get this figured out
Me@53 406 free( ptrToFree );
Me@53 407 }
Me@53 408
Me@53 409
Me@50 410 /*Designed to be called from the main thread outside of VMS, during init
Me@50 411 */
Me@50 412 MallocProlog *
Me@53 413 VMS_ext__create_free_list()
Me@50 414 { MallocProlog *freeListHead, *firstChunk;
msach@132 415
Me@50 416 //Note, this is running in the main thread -- all increases in malloc
Me@50 417 // mem and all frees of it must be done in this thread, with the
Me@50 418 // thread's original stack available
msach@134 419
Me@50 420 freeListHead = malloc( sizeof(MallocProlog) );
Me@50 421 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
Me@50 422 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
msach@79 423
msach@82 424 //Touch memory to avoid page faults
msach@81 425 void *ptr,*endPtr;
msach@81 426 endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
msach@81 427 for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE)
msach@81 428 {
msach@81 429 *(char*)ptr = 0;
msach@81 430 }
Me@50 431
Me@50 432 freeListHead->prevChunkInFreeList = NULL;
Me@50 433 //Use this addr to free the heap when cleanup
Me@50 434 freeListHead->nextLowerInMem = firstChunk;
Me@50 435 //to identify top-of-heap elem, compare this addr to elem's next higher
msach@76 436 freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
Me@53 437 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
Me@50 438 freeListHead->nextChunkInFreeList = firstChunk;
Me@50 439
Me@50 440 firstChunk->nextChunkInFreeList = NULL;
Me@50 441 firstChunk->prevChunkInFreeList = freeListHead;
Me@50 442 //next Higher has to be set to top of chunk, so can calc size in malloc
msach@76 443 firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
Me@53 444 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
Me@50 445 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
Me@53 446
Me@53 447 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
Me@50 448
Me@50 449 return freeListHead;
Me@50 450 }
Me@50 451
Me@50 452
Me@50 453 /*Designed to be called from the main thread outside of VMS, during cleanup
Me@50 454 */
Me@50 455 void
msach@135 456 VMS_ext__free_free_list( MallocProlog* freeListHead)
Me@50 457 {
Me@50 458 //stashed a ptr to the one and only bug chunk malloc'd from OS in the
Me@50 459 // free list head's next lower in mem pointer
msach@135 460 free( freeListHead->nextLowerInMem );
Me@50 461 //don't free the head -- it'll be in an array eventually -- free whole
Me@50 462 // array when all the free lists linked from it have already been freed
Me@50 463 }
Me@50 464