mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-22 12:01:25 +00:00
847 lines
16 KiB
C
847 lines
16 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// Z_zone.c
|
|
|
|
#include "quakedef.h"
|
|
#ifdef _WIN32
|
|
#include "winquake.h"
|
|
#endif
|
|
#ifdef __GLIBC__
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#define NOZONE
|
|
|
|
#ifdef _DEBUG
|
|
//#define MEMDEBUG 8192 //Debugging adds sentinels (the number is the size - I have the ram)
|
|
#endif
|
|
|
|
//must be multiple of 4.
|
|
//#define TEMPDEBUG 4
|
|
//#define ZONEDEBUG 4
|
|
//#define HUNKDEBUG 4
|
|
|
|
//these need to be defined because it makes some bits of code simpler
|
|
#ifndef HUNKDEBUG
|
|
#define HUNKDEBUG 0
|
|
#endif
|
|
#ifndef ZONEDEBUG
|
|
#define ZONEDEBUG 0
|
|
#endif
|
|
#ifndef TEMPDEBUG
|
|
#define TEMPDEBUG 0
|
|
#endif
|
|
|
|
#if ZONEDEBUG>0 || HUNKDEBUG>0 || TEMPDEBUG>0
|
|
qbyte sentinelkey;
|
|
#endif
|
|
|
|
#define TAGLESS 1
|
|
|
|
size_t zmemtotal;
|
|
size_t zmemdelta;
|
|
|
|
typedef struct memheader_s {
|
|
size_t size;
|
|
int tag;
|
|
} memheader_t;
|
|
|
|
typedef struct zone_s {
|
|
struct zone_s *next;
|
|
struct zone_s *pvdn; // down if first, previous if not
|
|
memheader_t mh;
|
|
} zone_t;
|
|
zone_t *zone_head;
|
|
#ifdef MULTITHREAD
|
|
void *zonelock;
|
|
#endif
|
|
|
|
#if 0
|
|
static void Z_DumpTree(void)
|
|
{
|
|
zone_t *zone;
|
|
zone_t *nextlist;
|
|
zone_t *t;
|
|
zone_t *prev;
|
|
|
|
zone = zone_head;
|
|
while(zone)
|
|
{
|
|
nextlist = zone->pvdn;
|
|
|
|
fprintf(stderr, " +-+ %016x (tag: %08x)\n", zone, zone->mh.tag);
|
|
|
|
prev = zone;
|
|
t = zone->next;
|
|
while(t)
|
|
{
|
|
if (t->pvdn != prev)
|
|
fprintf(stderr, "Previous link failure\n");
|
|
|
|
prev = t;
|
|
t = t->next;
|
|
}
|
|
|
|
while(zone)
|
|
{
|
|
fprintf(stderr, " +-- %016x\n", zone);
|
|
|
|
zone = zone->next;
|
|
}
|
|
|
|
zone = nextlist;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void *Z_TagMalloc(size_t size, int tag)
|
|
{
|
|
zone_t *zone;
|
|
|
|
zone = (zone_t *)malloc(size + sizeof(zone_t));
|
|
if (!zone)
|
|
Sys_Error("Z_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
|
|
Q_memset(zone, 0, size + sizeof(zone_t));
|
|
zone->mh.tag = tag;
|
|
zone->mh.size = size;
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_LockMutex(zonelock);
|
|
#endif
|
|
|
|
#if 0
|
|
fprintf(stderr, "Before alloc:\n");
|
|
Z_DumpTree();
|
|
fprintf(stderr, "\n");
|
|
#endif
|
|
|
|
if (zone_head == NULL)
|
|
zone_head = zone;
|
|
else
|
|
{
|
|
zone_t *s = zone_head;
|
|
|
|
while (s && s->mh.tag != tag)
|
|
s = s->pvdn;
|
|
|
|
if (s)
|
|
{ // tag match
|
|
zone->next = s->next;
|
|
if (s->next)
|
|
s->next->pvdn = zone;
|
|
zone->pvdn = s;
|
|
s->next = zone;
|
|
}
|
|
else
|
|
{
|
|
zone->pvdn = zone_head;
|
|
// if (s->next)
|
|
// s->next->pvdn = zone;
|
|
zone_head = zone;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
fprintf(stderr, "After alloc:\n");
|
|
Z_DumpTree();
|
|
fprintf(stderr, "\n");
|
|
#endif
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_UnlockMutex(zonelock);
|
|
#endif
|
|
|
|
return (void *)(zone + 1);
|
|
}
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
void *ZF_MallocNamed(int size, char *file, int line)
|
|
{
|
|
return _calloc_dbg(size, 1, _NORMAL_BLOCK, file, line);
|
|
}
|
|
void *Z_MallocNamed(int size, char *file, int line)
|
|
{
|
|
void *mem = ZF_MallocNamed(size, file, line);
|
|
if (!mem)
|
|
Sys_Error("Z_Malloc: Failed on allocation of %i bytes", size);
|
|
|
|
return mem;
|
|
}
|
|
#else
|
|
void *ZF_Malloc(size_t size)
|
|
{
|
|
#ifdef ANDROID
|
|
void *ret = NULL;
|
|
//android is linux, but not gnu and thus not posix...
|
|
ret = memalign(max(sizeof(float)*4, sizeof(void*)), size);
|
|
if (ret)
|
|
memset(ret, 0, size);
|
|
return ret;
|
|
#elif defined(__linux__)
|
|
void *ret = NULL;
|
|
|
|
if (!posix_memalign(&ret, max(sizeof(float)*4, sizeof(void*)), size))
|
|
memset(ret, 0, size);
|
|
return ret;
|
|
#else
|
|
return calloc(size, 1);
|
|
#endif
|
|
}
|
|
void *Z_Malloc(size_t size)
|
|
{
|
|
void *mem = ZF_Malloc(size);
|
|
if (!mem)
|
|
Sys_Error("Z_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
|
|
|
|
return mem;
|
|
}
|
|
#endif
|
|
|
|
char *Z_StrDupf(const char *format, ...)
|
|
{
|
|
va_list argptr;
|
|
char *string;
|
|
int n;
|
|
|
|
#if defined(_MSC_VER) || defined(_WIN32)
|
|
int try;
|
|
//msvc is shitty shit shit and doesn't even do c99. sadly mingw uses the same libraries.
|
|
try = 256;
|
|
for(;;)
|
|
{
|
|
string = Z_Malloc(try+1);
|
|
va_start (argptr, format);
|
|
n = _vsnprintf (string,try, format,argptr);
|
|
va_end (argptr);
|
|
if (n >= 0 && n < try)
|
|
break;
|
|
Z_Free(string);
|
|
try *= 2;
|
|
}
|
|
string[n] = 0;
|
|
#else
|
|
va_start (argptr, format);
|
|
n = vsnprintf (NULL,0, format,argptr);
|
|
va_end (argptr);
|
|
if (n < 0)
|
|
n = 1024; //windows bullshit. whatever. good luck with that.
|
|
|
|
string = Z_Malloc(n+1);
|
|
va_start (argptr, format);
|
|
vsnprintf (string,n+1, format,argptr);
|
|
va_end (argptr);
|
|
string[n] = 0;
|
|
#endif
|
|
|
|
return string;
|
|
}
|
|
void Z_StrCatLen(char **ptr, const char *append, size_t newlen)
|
|
{
|
|
size_t oldlen = *ptr?strlen(*ptr):0;
|
|
char *newptr = BZ_Malloc(oldlen+newlen+1);
|
|
memcpy(newptr, *ptr, oldlen);
|
|
memcpy(newptr+oldlen, append, newlen);
|
|
newptr[oldlen+newlen] = 0;
|
|
BZ_Free(*ptr);
|
|
*ptr = newptr;
|
|
}
|
|
void Z_StrCat(char **ptr, const char *append)
|
|
{
|
|
size_t oldlen = *ptr?strlen(*ptr):0;
|
|
size_t newlen = strlen(append);
|
|
char *newptr = BZ_Malloc(oldlen+newlen+1);
|
|
memcpy(newptr, *ptr, oldlen);
|
|
memcpy(newptr+oldlen, append, newlen);
|
|
newptr[oldlen+newlen] = 0;
|
|
BZ_Free(*ptr);
|
|
*ptr = newptr;
|
|
}
|
|
|
|
void VARGS Z_TagFree(void *mem)
|
|
{
|
|
zone_t *zone = ((zone_t *)mem) - 1;
|
|
|
|
#if 0
|
|
fprintf(stderr, "Before free:\n");
|
|
Z_DumpTree();
|
|
fprintf(stderr, "\n");
|
|
#endif
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_LockMutex(zonelock);
|
|
#endif
|
|
if (zone->next)
|
|
zone->next->pvdn = zone->pvdn;
|
|
|
|
if (zone->pvdn && zone->pvdn->mh.tag == zone->mh.tag)
|
|
zone->pvdn->next = zone->next;
|
|
else
|
|
{ // zone is first entry in a tag list
|
|
zone_t *s = zone_head;
|
|
|
|
if (zone != s)
|
|
{ // traverse and update down list
|
|
while (s->pvdn != zone)
|
|
s = s->pvdn;
|
|
|
|
if (zone->next)
|
|
s->pvdn = zone->next;
|
|
else
|
|
s->pvdn = zone->pvdn;
|
|
}
|
|
}
|
|
|
|
if (zone == zone_head)
|
|
{ // freeing head node so update head pointer
|
|
if (zone->next) // move to next, pvdn should be maintained properly
|
|
zone_head = zone->next;
|
|
else // no more entries with this tag so move head down
|
|
zone_head = zone->pvdn;
|
|
}
|
|
|
|
#if 0
|
|
fprintf(stderr, "After free:\n");
|
|
Z_DumpTree();
|
|
fprintf(stderr, "\n");
|
|
#endif
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_UnlockMutex(zonelock);
|
|
#endif
|
|
|
|
free(zone);
|
|
}
|
|
|
|
void VARGS Z_Free(void *mem)
|
|
{
|
|
free(mem);
|
|
}
|
|
|
|
void VARGS Z_FreeTags(int tag)
|
|
{
|
|
zone_t *taglist;
|
|
zone_t *t;
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_LockMutex(zonelock);
|
|
#endif
|
|
if (zone_head)
|
|
{
|
|
if (zone_head->mh.tag == tag)
|
|
{ // just pull off the head
|
|
taglist = zone_head;
|
|
zone_head = zone_head->pvdn;
|
|
}
|
|
else
|
|
{ // search for tag list and isolate it
|
|
zone_t *z;
|
|
z = zone_head;
|
|
while (z->pvdn != NULL && z->pvdn->mh.tag != tag)
|
|
z = z->pvdn;
|
|
|
|
if (z->pvdn == NULL)
|
|
taglist = NULL;
|
|
else
|
|
{
|
|
taglist = z->pvdn;
|
|
z->pvdn = z->pvdn->pvdn;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
taglist = NULL;
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
Sys_UnlockMutex(zonelock);
|
|
#endif
|
|
|
|
// actually free list
|
|
while (taglist != NULL)
|
|
{
|
|
t = taglist->next;
|
|
free(taglist);
|
|
taglist = t;
|
|
}
|
|
}
|
|
|
|
//close enough
|
|
#ifndef SIZE_MAX
|
|
#define SIZE_MAX ((size_t)-1)
|
|
#endif
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
qboolean ZF_ReallocElementsNamed(void **ptr, size_t *elements, size_t newelements, size_t elementsize, const char *file, int line)
|
|
#else
|
|
qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize)
|
|
#endif
|
|
{
|
|
void *n;
|
|
size_t oldsize;
|
|
size_t newsize;
|
|
|
|
//protect against malicious overflows
|
|
if (newelements > SIZE_MAX / elementsize)
|
|
return false;
|
|
|
|
oldsize = *elements * elementsize;
|
|
newsize = newelements * elementsize;
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
n = BZ_ReallocNamed(*ptr, newsize, file, line);
|
|
#else
|
|
n = BZ_Realloc(*ptr, newsize);
|
|
#endif
|
|
if (!n)
|
|
return false;
|
|
if (newsize > oldsize)
|
|
memset((char*)n+oldsize, 0, newsize - oldsize);
|
|
*elements = newelements;
|
|
*ptr = n;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
void *Z_Realloc(void *data, int newsize)
|
|
{
|
|
memheader_t *memref;
|
|
|
|
if (!data)
|
|
return Z_Malloc(newsize);
|
|
|
|
memref = ((memheader_t *)data) - 1;
|
|
|
|
if (memref[0].tag != TAGLESS)
|
|
{ // allocate a new block and copy since we need to maintain the lists
|
|
zone_t *zone = ((zone_t *)data) - 1;
|
|
int size = zone->mh.size;
|
|
if (size != newsize)
|
|
{
|
|
void *newdata = Z_Malloc(newsize);
|
|
|
|
if (size > newsize)
|
|
size = newsize;
|
|
memcpy(newdata, data, size);
|
|
|
|
Z_Free(data);
|
|
data = newdata;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int oldsize = memref[0].size;
|
|
memref = realloc(memref, newsize + sizeof(memheader_t));
|
|
memref->size = newsize;
|
|
if (newsize > oldsize)
|
|
memset((qbyte *)memref + sizeof(memheader_t) + oldsize, 0, newsize - oldsize);
|
|
data = ((memheader_t *)memref) + 1;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
*/
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
void *BZF_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but allowed to fail - like straight malloc.
|
|
{
|
|
void *mem;
|
|
mem = _malloc_dbg(size, _NORMAL_BLOCK, file, line);
|
|
if (mem)
|
|
{
|
|
zmemdelta += size;
|
|
zmemtotal += size;
|
|
}
|
|
return mem;
|
|
}
|
|
#else
|
|
void *BZF_Malloc(size_t size) //BZ_Malloc but allowed to fail - like straight malloc.
|
|
{
|
|
void *mem;
|
|
mem = malloc(size);
|
|
if (mem)
|
|
{
|
|
zmemdelta += size;
|
|
zmemtotal += size;
|
|
}
|
|
return mem;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
void *BZ_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but allowed to fail - like straight malloc.
|
|
{
|
|
void *mem = BZF_MallocNamed(size, file, line);
|
|
if (!mem)
|
|
Sys_Error("BZ_Malloc: Failed on allocation of %i bytes", size);
|
|
|
|
return mem;
|
|
}
|
|
#else
|
|
void *BZ_Malloc(size_t size) //Doesn't clear. The expectation is a large file, rather than sensitive data structures.
|
|
{
|
|
void *mem = BZF_Malloc(size);
|
|
if (!mem)
|
|
Sys_Error("BZ_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
|
|
|
|
return mem;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
void *BZF_ReallocNamed(void *data, int newsize, const char *file, int line)
|
|
{
|
|
return _realloc_dbg(data, newsize, _NORMAL_BLOCK, file, line);
|
|
}
|
|
|
|
void *BZ_ReallocNamed(void *data, int newsize, const char *file, int line)
|
|
{
|
|
void *mem = BZF_ReallocNamed(data, newsize, file, line);
|
|
|
|
if (!mem)
|
|
Sys_Error("BZ_Realloc: Failed on reallocation of %i bytes", newsize);
|
|
|
|
return mem;
|
|
}
|
|
#else
|
|
void *BZF_Realloc(void *data, size_t newsize)
|
|
{
|
|
return realloc(data, newsize);
|
|
}
|
|
|
|
void *BZ_Realloc(void *data, size_t newsize)
|
|
{
|
|
void *mem = BZF_Realloc(data, newsize);
|
|
|
|
if (!mem)
|
|
Sys_Error("BZ_Realloc: Failed on reallocation of %"PRIuSIZE" bytes", newsize);
|
|
|
|
return mem;
|
|
}
|
|
#endif
|
|
|
|
void BZ_Free(void *data)
|
|
{
|
|
free(data);
|
|
}
|
|
|
|
|
|
typedef struct zonegroupblock_s
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
struct zonegroupblock_s *next;
|
|
struct zonegroupblock_s *prev;
|
|
#ifdef _DEBUG
|
|
#define ZONEGROUP_SENTINAL 0x709ef00d
|
|
unsigned int sentinal;
|
|
unsigned int size;
|
|
#endif
|
|
};
|
|
vec4_t align16;
|
|
};
|
|
} zonegroupblock_t;
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
#undef ZG_Malloc
|
|
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size){return ZG_MallocNamed(ctx, size, "ZG_Malloc", size);}
|
|
void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line)
|
|
#else
|
|
void *QDECL ZG_Malloc(zonegroup_t *ctx, size_t size)
|
|
#endif
|
|
{
|
|
zonegroupblock_t *newm;
|
|
size += sizeof(zonegroupblock_t); //well, at least the memory will be pointer aligned...
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
newm = Z_MallocNamed(size, file, line);
|
|
#else
|
|
newm = Z_Malloc(size);
|
|
#endif
|
|
|
|
newm->prev = NULL;
|
|
if (ctx->first)
|
|
((zonegroupblock_t*)ctx->first)->prev = newm;
|
|
newm->next = ctx->first;
|
|
ctx->first = newm;
|
|
ctx->totalbytes += size;
|
|
|
|
#ifdef _DEBUG
|
|
newm->sentinal = ZONEGROUP_SENTINAL;
|
|
newm->size = size;
|
|
#endif
|
|
return(void*)(newm+1);
|
|
}
|
|
void ZG_Free(zonegroup_t *ctx, void *ptr)
|
|
{
|
|
zonegroupblock_t *mem = (zonegroupblock_t*)ptr-1;
|
|
if (mem->prev)
|
|
mem->prev->next = mem->next;
|
|
else
|
|
ctx->first = mem->next;
|
|
if (mem->next)
|
|
mem->next->prev = mem->prev;
|
|
|
|
#ifdef _DEBUG
|
|
if (mem->sentinal != ZONEGROUP_SENTINAL)
|
|
Sys_Error("Corrupt memory");
|
|
ctx->totalbytes -= mem->size;
|
|
#endif
|
|
BZ_Free(mem);
|
|
}
|
|
void ZG_FreeGroup(zonegroup_t *ctx)
|
|
{
|
|
zonegroupblock_t *old;
|
|
while(ctx->first)
|
|
{
|
|
old = ctx->first;
|
|
ctx->first = old->next;
|
|
BZ_Free(old);
|
|
}
|
|
ctx->totalbytes = 0;
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
/*
|
|
=================
|
|
Hunk_TempAlloc
|
|
|
|
Return space from the top of the hunk
|
|
clears old temp.
|
|
=================
|
|
*/
|
|
typedef struct hnktemps_s {
|
|
struct hnktemps_s *next;
|
|
#if TEMPDEBUG>0
|
|
int len;
|
|
#endif
|
|
} hnktemps_t;
|
|
hnktemps_t *hnktemps;
|
|
|
|
void Hunk_TempFree(void)
|
|
{
|
|
hnktemps_t *nt;
|
|
|
|
COM_AssertMainThread("Hunk_TempFree");
|
|
|
|
while (hnktemps)
|
|
{
|
|
#if TEMPDEBUG>0
|
|
int i;
|
|
qbyte *buf;
|
|
buf = (qbyte *)(hnktemps+1);
|
|
for (i = 0; i < TEMPDEBUG; i++)
|
|
{
|
|
if (buf[i] != sentinelkey)
|
|
Sys_Error ("Hunk_Check: corrupt sentinel");
|
|
}
|
|
buf+=TEMPDEBUG;
|
|
//app data
|
|
buf += hnktemps->len;
|
|
for (i = 0; i < TEMPDEBUG; i++)
|
|
{
|
|
if (buf[i] != sentinelkey)
|
|
Sys_Error ("Hunk_Check: corrupt sentinel");
|
|
}
|
|
#endif
|
|
|
|
nt = hnktemps->next;
|
|
|
|
free(hnktemps);
|
|
hnktemps = nt;
|
|
}
|
|
}
|
|
|
|
|
|
//allocates without clearing previous temp.
|
|
//safer than my hack that fuh moaned about...
|
|
void *Hunk_TempAllocMore (size_t size)
|
|
{
|
|
void *buf;
|
|
|
|
#if TEMPDEBUG>0
|
|
hnktemps_t *nt;
|
|
COM_AssertMainThread("Hunk_TempAllocMore");
|
|
nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t) + TEMPDEBUG*2);
|
|
if (!nt)
|
|
return NULL;
|
|
nt->next = hnktemps;
|
|
nt->len = size;
|
|
hnktemps = nt;
|
|
buf = (void *)(nt+1);
|
|
memset(buf, sentinelkey, TEMPDEBUG);
|
|
buf = (char *)buf + TEMPDEBUG;
|
|
memset(buf, 0, size);
|
|
memset((char *)buf + size, sentinelkey, TEMPDEBUG);
|
|
return buf;
|
|
#else
|
|
hnktemps_t *nt;
|
|
COM_AssertMainThread("Hunk_TempAllocMore");
|
|
nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t));
|
|
if (!nt)
|
|
return NULL;
|
|
nt->next = hnktemps;
|
|
hnktemps = nt;
|
|
buf = (void *)(nt+1);
|
|
memset(buf, 0, size);
|
|
return buf;
|
|
#endif
|
|
}
|
|
|
|
|
|
void *Hunk_TempAlloc (size_t size)
|
|
{
|
|
Hunk_TempFree();
|
|
|
|
return Hunk_TempAllocMore(size);
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
CACHE MEMORY
|
|
|
|
===============================================================================
|
|
*/
|
|
void Cache_Flush(void)
|
|
{
|
|
//this generically named function is hyjacked to flush models and sounds, as well as ragdolls etc
|
|
#ifdef HAVE_CLIENT
|
|
S_Purge(false);
|
|
#endif
|
|
#if defined(HAVE_CLIENT) || defined(HAVE_SERVER)
|
|
#ifdef RAGDOLL
|
|
rag_flushdolls(true);
|
|
#endif
|
|
Mod_Purge(MP_FLUSH);
|
|
#endif
|
|
#ifdef HAVE_CLIENT
|
|
Image_Purge();
|
|
#endif
|
|
|
|
#ifdef __GLIBC__
|
|
malloc_trim(0);
|
|
#endif
|
|
}
|
|
|
|
static void Hunk_Print_f (void)
|
|
{
|
|
Con_Printf("Z Delta: %"PRIuSIZE"KB\n", zmemdelta/1024); zmemdelta = 0;
|
|
Con_Printf("Z Total: %"PRIuSIZE"KB\n", zmemtotal/1024);
|
|
//note: Zone memory isn't tracked reliably. we don't track the mem that is freed, so it'll just climb and climb
|
|
//we don't track reallocs either.
|
|
|
|
#if 0
|
|
{
|
|
zone_t *zone;
|
|
int zoneused = 0;
|
|
int zoneblocks = 0;
|
|
|
|
for(zone = zone_head; zone; zone=zone->next)
|
|
{
|
|
zoneused += zone->size + sizeof(zone_t);
|
|
zoneblocks++;
|
|
}
|
|
Con_Printf("Zone: %i containing %iKB\n", zoneblocks, zoneused/1024);
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_MSVCRT_DEBUG
|
|
{
|
|
static struct _CrtMemState savedstate;
|
|
static qboolean statesaved;
|
|
|
|
_CrtMemDumpAllObjectsSince(statesaved?&savedstate:NULL);
|
|
_CrtMemCheckpoint(&savedstate);
|
|
statesaved = true;
|
|
}
|
|
#endif
|
|
}
|
|
void Cache_Init(void)
|
|
{
|
|
Cmd_AddCommand ("flush", Cache_Flush);
|
|
Cmd_AddCommand ("hunkprint", Hunk_Print_f);
|
|
#if 0
|
|
Cmd_AddCommand ("zoneprint", Zone_Print_f);
|
|
#endif
|
|
#ifdef NAMEDMALLOCS
|
|
Cmd_AddCommand ("zonegroups", Zone_Groups_f);
|
|
#endif
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
/*
|
|
========================
|
|
Memory_Init
|
|
========================
|
|
*/
|
|
void Memory_Init (void)
|
|
{
|
|
#if 0 //ndef NOZONE
|
|
int p;
|
|
int zonesize = DYNAMIC_SIZE;
|
|
#endif
|
|
|
|
#if ZONEDEBUG>0 || HUNKDEBUG>0 || TEMPDEBUG>0||CACHEDEBUG>0
|
|
srand(time(0));
|
|
sentinelkey = rand() & 0xff;
|
|
#endif
|
|
|
|
Cache_Init ();
|
|
|
|
#ifdef MULTITHREAD
|
|
if (!zonelock)
|
|
zonelock = Sys_CreateMutex(); // this can fail!
|
|
#endif
|
|
|
|
#if 0 //ndef NOZONE
|
|
p = COM_CheckParm ("-zone");
|
|
if (p)
|
|
{
|
|
if (p < com_argc-1)
|
|
zonesize = Q_atoi (com_argv[p+1]) * 1024;
|
|
else
|
|
Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
|
|
}
|
|
mainzone = Hunk_AllocName ( zonesize, "zone" );
|
|
Z_ClearZone (mainzone, zonesize);
|
|
#endif
|
|
}
|
|
|
|
void Memory_DeInit(void)
|
|
{
|
|
Hunk_TempFree();
|
|
Cache_Flush();
|
|
|
|
#ifdef MULTITHREAD
|
|
if (zonelock)
|
|
{
|
|
Sys_DestroyMutex(zonelock);
|
|
zonelock = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|