annotate vmalloc.c @ 135:0b49fd35afc1

distributed free working -app sends a VMSSemReqst to his Master which send a request to a different Master -Master send the request directly -The request structure is freed by the sender, when the request was handled There are still problems on shutdown. The shutdownVPs are all allocated by one Master which is likly to be terminated
author Merten Sach <msach@mailbox.tu-berlin.de>
date Fri, 16 Sep 2011 20:08:28 +0200
parents a9b72021f053
children 99343ffe1918
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@78 106 { ERROR("\nmalloc failed\n")
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