// Frees a block of memory... // void Z_Free(void *pvAddress) { zoneHeader_t *pMemory = ((zoneHeader_t *)pvAddress) - 1; if (pMemory->eTag == TAG_STATIC) { return; } #ifdef DETAILED_ZONE_DEBUG_CODE // // check this error *before* barfing on bad magics... // int& iAllocCount = mapAllocatedZones[pMemory]; if (iAllocCount <= 0) { Com_Error(ERR_FATAL, "Z_Free(): Block already-freed, or not allocated through Z_Malloc!"); return; } #endif if (pMemory->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone header!"); return; } if (ZoneTailFromHeader(pMemory)->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone tail!"); return; } Zone_FreeBlock(pMemory); }
void Z_Validate(void) { if(!com_validateZone || !com_validateZone->integer) { return; } zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { #ifdef DETAILED_ZONE_DEBUG_CODE // this won't happen here, but wtf? int& iAllocCount = mapAllocatedZones[pMemory]; if (iAllocCount <= 0) { Com_Error(ERR_FATAL, "Z_Validate(): Bad block allocation count!"); return; } #endif if(pMemory->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Validate(): Corrupt zone header!"); return; } if (ZoneTailFromHeader(pMemory)->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Validate(): Corrupt zone tail!"); return; } pMemory = pMemory->pNext; } }
int Z_Validate(void) { int ret=0; if(!com_validateZone || !com_validateZone->integer) { return ret; } zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { #ifdef DETAILED_ZONE_DEBUG_CODE // this won't happen here, but wtf? int& iAllocCount = mapAllocatedZones[pMemory]; if (iAllocCount <= 0) { Com_Error(ERR_FATAL, "Z_Validate(): Bad block allocation count!"); return ret; } #endif if(pMemory->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Validate(): Corrupt zone header!"); return ret; } // this block of code is intended to make sure all of the data is paged in if (pMemory->eTag != TAG_IMAGE_T && pMemory->eTag != TAG_MODEL_MD3 && pMemory->eTag != TAG_MODEL_GLM && pMemory->eTag != TAG_MODEL_GLA ) //don't bother with disk caches as they've already been hit or will be thrown out next { unsigned char *memstart = (unsigned char *)pMemory; int totalSize = pMemory->iSize; while (totalSize > 4096) { memstart += 4096; ret += (int)(*memstart); // this fools the optimizer totalSize -= 4096; } } if (ZoneTailFromHeader(pMemory)->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Validate(): Corrupt zone tail!"); return ret; } pMemory = pMemory->pNext; } return ret; }
// Frees a block of memory... // int Z_Free(void *pvAddress) { if (!TheZone.Stats.iCount) { //Com_Error(ERR_FATAL, "Z_Free(): Zone has been cleard already!"); Com_Printf("Z_Free(%x): Zone has been cleard already!\n",pvAddress); return -1; } zoneHeader_t *pMemory = ((zoneHeader_t *)pvAddress) - 1; #if 1 //debugging double free if (pMemory->iMagic == 'FREE') { Com_Error(ERR_FATAL, "Z_Free(%s): Block already-freed, or not allocated through Z_Malloc!",pvAddress); return -1; } #endif if (pMemory->eTag == TAG_STATIC) { return 0; } #ifdef DETAILED_ZONE_DEBUG_CODE // // check this error *before* barfing on bad magics... // int& iAllocCount = mapAllocatedZones[pMemory]; if (iAllocCount <= 0) { Com_Error(ERR_FATAL, "Z_Free(): Block already-freed, or not allocated through Z_Malloc!"); return -1; } #endif if (pMemory->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone header!"); return -1; } if (ZoneTailFromHeader(pMemory)->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone tail!"); return -1; } return Zone_FreeBlock(pMemory); }
// Frees a block of memory... // void Z_Free(void *pvAddress) { if (pvAddress == NULL) // I've put this in as a safety measure because of some bits of #ifdef BSPC stuff -Ste. { //Com_Error(ERR_FATAL, "Z_Free(): NULL arg"); return; } zoneHeader_t *pMemory = ((zoneHeader_t *)pvAddress) - 1; if (pMemory->eTag == TAG_STATIC) { return; } #ifdef DETAILED_ZONE_DEBUG_CODE // // check this error *before* barfing on bad magics... // int& iAllocCount = mapAllocatedZones[pMemory]; if (iAllocCount <= 0) { Com_Error(ERR_FATAL, "Z_Free(): Block already-freed, or not allocated through Z_Malloc!"); return; } #endif if (pMemory->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone header!"); return; } if (ZoneTailFromHeader(pMemory)->iMagic != ZONE_MAGIC) { Com_Error(ERR_FATAL, "Z_Free(): Corrupt zone tail!"); return; } Zone_FreeBlock(pMemory); }
void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit) #endif { gbMemFreeupOccured = qfalse; if (iSize == 0) { zoneHeader_t *pMemory = (zoneHeader_t *) &gZeroMalloc; return &pMemory[1]; } // Add in tracking info and round to a longword... (ignore longword aligning now we're not using contiguous blocks) // // int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t) + 3) & 0xfffffffc; int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t)); // Allocate a chunk... // zoneHeader_t *pMemory = NULL; while (pMemory == NULL) { #ifdef _WIN32 if (gbMemFreeupOccured) { Sleep(100); // sleep for 1/10 of a second, so Windows has a chance to shuffle mem to de-swiss-cheese it } #endif pMemory = (zoneHeader_t *) malloc ( iRealSize ); if (!pMemory) { // new bit, if we fail to malloc memory, try dumping some of the cached stuff that's non-vital and try again... // // ditch the BSP cache... // if (CM_DeleteCachedMap(qfalse)) { gbMemFreeupOccured = qtrue; continue; // we've just ditched a whole load of memory, so try again with the malloc } // ditch any sounds not used on this level... // extern qboolean SND_RegisterAudio_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (SND_RegisterAudio_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one sound, so try again with the malloc } // ditch any image_t's (and associated GL texture mem) not used on this level... // extern qboolean RE_RegisterImages_LevelLoadEnd(void); if (RE_RegisterImages_LevelLoadEnd()) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one image, so try again with the malloc } // ditch the model-binaries cache... (must be getting desperate here!) // extern qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (RE_RegisterModels_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; } // as a last panic measure, dump all the audio memory, but not if we're in the audio loader // (which is annoying, but I'm not sure how to ensure we're not dumping any memory needed by the sound // currently being loaded if that was the case)... // // note that this keeps querying until it's freed up as many bytes as the requested size, but freeing // several small blocks might not mean that one larger one is satisfiable after freeup, however that'll // just make it go round again and try for freeing up another bunch of blocks until the total is satisfied // again (though this will have freed twice the requested amount in that case), so it'll either work // eventually or not free up enough and drop through to the final ERR_DROP. No worries... // extern qboolean gbInsideLoadSound; extern int SND_FreeOldestSound(void); // I had to add a void-arg version of this because of link issues, sigh if (!gbInsideLoadSound) { int iBytesFreed = SND_FreeOldestSound(); if (iBytesFreed) { int iTheseBytesFreed = 0; while ( (iTheseBytesFreed = SND_FreeOldestSound()) != 0) { iBytesFreed += iTheseBytesFreed; if (iBytesFreed >= iRealSize) break; // early opt-out since we've managed to recover enough (mem-contiguity issues aside) } gbMemFreeupOccured = qtrue; continue; } } // sigh, dunno what else to try, I guess we'll have to give up and report this as an out-of-mem error... // // findlabel: "recovermem" Com_Printf(S_COLOR_RED"Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); Z_Details_f(); Com_Error(ERR_FATAL,"(Repeat): Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); return NULL; } } #ifdef DEBUG_ZONE_ALLOCS extern char *Filename_WithoutPath(const char *psFilename); Q_strncpyz(pMemory->sSrcFileBaseName, Filename_WithoutPath(psFile), sizeof(pMemory->sSrcFileBaseName)); pMemory->iSrcFileLineNum = iLine; pMemory->sOptionalLabel[0] = '\0'; pMemory->iSnapshotNumber = giZoneSnaphotNum; #endif // Link in pMemory->iMagic = ZONE_MAGIC; pMemory->eTag = eTag; pMemory->iSize = iSize; pMemory->pNext = TheZone.Header.pNext; TheZone.Header.pNext = pMemory; if (pMemory->pNext) { pMemory->pNext->pPrev = pMemory; } pMemory->pPrev = &TheZone.Header; // // add tail... // ZoneTailFromHeader(pMemory)->iMagic = ZONE_MAGIC; // Update stats... // TheZone.Stats.iCurrent += iSize; TheZone.Stats.iCount++; TheZone.Stats.iSizesPerTag [eTag] += iSize; TheZone.Stats.iCountsPerTag [eTag]++; if (TheZone.Stats.iCurrent > TheZone.Stats.iPeak) { TheZone.Stats.iPeak = TheZone.Stats.iCurrent; } #ifdef DETAILED_ZONE_DEBUG_CODE mapAllocatedZones[pMemory]++; #endif Z_Validate(); // check for corruption void *pvReturnMem = &pMemory[1]; if (bZeroit) { memset(pvReturnMem, 0, iSize); } return pvReturnMem; }