31#define MEMHEADER_SENTINEL_FOR_ADDRESS(p) ((sentinel_seed ^ (unsigned int) (uintptr_t) (p)) + sentinel_seed)
38#ifndef FILE_BACKED_MALLOC
39# define FILE_BACKED_MALLOC 0
46#ifndef MEMCLUMPING_FREECLUMPS
47# define MEMCLUMPING_FREECLUMPS 0
54#ifndef MEMWANTCLUMPSIZE
55# define MEMWANTCLUMPSIZE (1<<27)
58#define MEMCLUMPSIZE (MEMWANTCLUMPSIZE - MEMWANTCLUMPSIZE/MEMUNIT/32 - 128)
59#define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
60#define MEMBITINTS (MEMBITS / 32)
62typedef struct memclump_s
65 unsigned char block[MEMCLUMPSIZE];
67 unsigned int sentinel1;
70 unsigned int bits[MEMBITINTS];
72 unsigned int sentinel2;
77 size_t largestavailable;
79 struct memclump_s *
chain;
84static memclump_t masterclump;
86static memclump_t *clumpchain =
NULL;
101#if FILE_BACKED_MALLOC
105#define MAP_NORESERVE 0
107typedef struct mmap_data_s
112static void *mmap_malloc(
size_t size)
115 char *tmpdir = getenv(
"TEMP");
118 size +=
sizeof(mmap_data_t);
119 dpsnprintf(vabuf,
sizeof(vabuf),
"%s/darkplaces.XXXXXX", tmpdir ? tmpdir :
"/tmp");
124 data = (
unsigned char *) mmap(
NULL,
size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
130 return (
void *) (
data + 1);
132static void mmap_free(
void *mem)
137 data = ((mmap_data_t *) mem) - 1;
140#define malloc mmap_malloc
141#define free mmap_free
154 unsigned int attempts = 500;
157 base = (
void *)malloc(
size);
168static memclump_t *Clump_NewClump(
void)
170 memclump_t **clumpchainpointer;
175 clump = &masterclump;
184 memset(clump, 0xEF,
sizeof(*clump));
186 memset(clump->bits, 0,
sizeof(clump->bits));
188 clump->blocksinuse = 0;
189 clump->largestavailable = 0;
193 for (clumpchainpointer = &clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
195 *clumpchainpointer = clump;
206 if (
size <= MEMCLUMPSIZE)
219 memclump_t **clumpchainpointer;
221 needbits = (
size + MEMUNIT - 1) / MEMUNIT;
222 needints = (needbits+31)>>5;
223 for (clumpchainpointer = &clumpchain;;clumpchainpointer = &(*clumpchainpointer)->chain)
225 clump = *clumpchainpointer;
228 clump = Clump_NewClump();
233 Sys_Error(
"Clump_AllocBlock: trashed sentinel1\n");
235 Sys_Error(
"Clump_AllocBlock: trashed sentinel2\n");
237 endbit = startbit + needbits;
244 endindex = MEMBITINTS;
245 startindex = endindex - needints;
247 while (--
index >= startindex)
252 startindex = endindex - needints;
257 startbit = startindex*32;
264 mask = (1<<needbits)-1;
265 endbit = 32-needbits;
270 if (
value != 0xFFFFFFFFu)
273 for (bit = 0;bit < endbit;bit++)
277 startbit =
index*32+bit;
286 endbit = startbit + needbits;
289 for (bit = startbit;bit < endbit;bit++)
290 if (clump->bits[bit>>5] & (1<<(bit & 31)))
291 Sys_Error(
"Clump_AllocBlock: internal error (%i needbits)\n", needbits);
292 for (bit = startbit;bit < endbit;bit++)
293 clump->bits[bit>>5] |= (1<<(bit & 31));
294 clump->blocksinuse += needbits;
295 base = clump->block + startbit * MEMUNIT;
297 memset(base, 0xBF, needbits * MEMUNIT);
312 memset(base, 0xAF,
size);
323 memclump_t **clumpchainpointer;
325 unsigned char *start = (
unsigned char *)base;
326 for (clumpchainpointer = &clumpchain;(clump = *clumpchainpointer);clumpchainpointer = &(*clumpchainpointer)->chain)
328 if (start >= clump->block && start < clump->block + MEMCLUMPSIZE)
331 Sys_Error(
"Clump_FreeBlock: trashed sentinel1\n");
333 Sys_Error(
"Clump_FreeBlock: trashed sentinel2\n");
334 if (start +
size > clump->block + MEMCLUMPSIZE)
335 Sys_Error(
"Clump_FreeBlock: block overrun\n");
337 needbits = (
size + MEMUNIT - 1) / MEMUNIT;
338 startbit = (start - clump->block) / MEMUNIT;
339 endbit = startbit + needbits;
341 for (bit = startbit;bit < endbit;bit++)
342 if ((clump->bits[bit>>5] & (1<<(bit & 31))) == 0)
343 Sys_Error(
"Clump_FreeBlock: double free\n");
344 for (bit = startbit;bit < endbit;bit++)
345 clump->bits[bit>>5] &= ~(1<<(bit & 31));
346 clump->blocksinuse -= needbits;
347 memset(base, 0xFF, needbits * MEMUNIT);
349 if (clump->blocksinuse == 0)
351 *clumpchainpointer = clump->chain;
353 memset(clump, 0xFF,
sizeof(*clump));
364 memset(base, 0xFF,
size);
371 unsigned int sentinel1;
372 unsigned int sentinel2;
391 Sys_Error(
"Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline);
396 Con_DPrintf(
"Mem_Alloc: pool %s, file %s:%i, size %f bytes (%f MB)\n", pool->
name, filename, fileline, (
double)
size, (
double)
size / 1048576.0f);
409 Sys_Error(
"Mem_Alloc: out of memory (alloc of size %f (%.3fMB) at %s:%i)", (
double)realsize, (
double)realsize / (1 << 20), filename, fileline);
423 memcpy((
unsigned char *) mem +
sizeof(
memheader_t) + mem->
size, &sentinel2,
sizeof(sentinel2));
439 remainsize -= sharedsize;
442 memset((
void *)((
unsigned char *) mem +
sizeof(
memheader_t) + sharedsize), 0, remainsize);
443 return (
void *)((
unsigned char *) mem +
sizeof(
memheader_t));
452 unsigned int sentinel1;
453 unsigned int sentinel2;
459 Sys_Error(
"Mem_Free: trashed head sentinel (alloc at %s:%i, free at %s:%i)", mem->
filename, mem->
fileline, filename, fileline);
460 if (memcmp((
unsigned char *) mem +
sizeof(
memheader_t) + mem->
size, &sentinel2,
sizeof(sentinel2)))
461 Sys_Error(
"Mem_Free: trashed tail sentinel (alloc at %s:%i, free at %s:%i)", mem->
filename, mem->
fileline, filename, fileline);
467 if (mem->
list.prev->next != &mem->
list || mem->
list.next->prev != &mem->
list)
468 Sys_Error(
"Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline);
486 Con_DPrintf(
"Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline);
494 Sys_Error(
"Mem_Free: data is not allocated (called at %s:%i)", filename, fileline);
512 Sys_Error(
"Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline);
540 for (chainaddress = &
poolchain;*chainaddress && *chainaddress != pool;chainaddress = &((*chainaddress)->next));
541 if (*chainaddress != pool)
542 Sys_Error(
"Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline);
544 Sys_Error(
"Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
546 Sys_Error(
"Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
547 *chainaddress = pool->
next;
554 for(iter =
poolchain; iter; iter = temp) {
575 for (chainaddress =
poolchain;chainaddress;chainaddress = chainaddress->
next)
576 if (chainaddress == pool)
579 Sys_Error(
"Mem_EmptyPool: pool is already free (emptypool at %s:%i)", filename, fileline);
582 Sys_Error(
"Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline);
584 Sys_Error(
"Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
586 Sys_Error(
"Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
593 for(chainaddress =
poolchain; chainaddress; chainaddress = chainaddress->
next)
594 if(chainaddress->
parent == pool)
602 unsigned int sentinel1;
603 unsigned int sentinel2;
606 Sys_Error(
"Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline);
612 Sys_Error(
"Mem_Free: trashed head sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->
filename, mem->
fileline, filename, fileline);
613 if (memcmp((
unsigned char *) mem +
sizeof(
memheader_t) + mem->
size, &sentinel2,
sizeof(sentinel2)))
614 Sys_Error(
"Mem_Free: trashed tail sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->
filename, mem->
fileline, filename, fileline);
618static void _Mem_CheckClumpSentinels(memclump_t *clump,
const char *filename,
int fileline)
622 Sys_Error(
"Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i)", filename, fileline);
624 Sys_Error(
"Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)", filename, fileline);
638 Sys_Error(
"Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
640 Sys_Error(
"Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->
filename, pool->
fileline, filename, fileline);
647 for (clump = clumpchain;clump;clump = clump->chain)
648 _Mem_CheckClumpSentinels(clump, filename, fileline);
677 memset(l, 0,
sizeof(*l));
692 memset(l, 0,
sizeof(*l));
746 unsigned char *p = (
unsigned char *)record;
753 Sys_Error(
"Mem_ExpandableArray_FreeRecord: no such record %p\n", (
void *)p);
755 Sys_Error(
"Mem_ExpandableArray_FreeRecord: record %p is already free!\n", (
void *)p);
765 size_t i, j, k, end = 0;
800 size_t count = 0,
size = 0, realsize = 0;
810 Con_Printf(
"%lu memory pools, totalling %lu bytes (%.3fMB)\n", (
unsigned long)
count, (
unsigned long)
size,
size / 1048576.0);
811 Con_Printf(
"total allocated size: %lu bytes (%.3fMB)\n", (
unsigned long)realsize, realsize / 1048576.0);
816 Con_Printf(
CON_WARN "Memory pool %p has sprung a leak totalling %lu bytes (%.3fMB)! Listing contents...\n", (
void *)pool, (
unsigned long)pool->
totalsize, pool->totalsize / 1048576.0);
835 if (mem->
size >= minallocationsize)
853 Con_Print(
"MemList_f: unrecognized options\nusage: memlist [all]\n");
872 p = (
char*)
_Mem_Alloc (pool,
NULL, sz,
alignof(
char), filename, fileline);
884 static union {
unsigned short s;
unsigned char b[2];} u;
910 Cmd_AddCommand(
CF_SHARED,
"memlist",
MemList_f,
"prints memory pool information (or if used as memlist 5 lists individual allocations of 5K or larger, 0 lists all allocations)");
921 MEMORYSTATUSEX status;
925 status.dwLength =
sizeof(status);
926 if(GlobalMemoryStatusEx(&status))
938 status.dwLength =
sizeof(status);
939 GlobalMemoryStatus(&status);
951 FILE *
f =
fopen(
"/proc/meminfo",
"r");
954 static char buf[1024];
static unsigned char olddata[NET_MAXMESSAGE]
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
#define CF_READONLY
cvar cannot be changed from the console or the command buffer, and is considered CF_PERSISTENT
#define CF_SERVER
cvar/command that only the server can change/execute
static int Cmd_Argc(cmd_state_t *cmd)
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
#define CF_CLIENT
cvar/command that only the client can change/execute
static void List_Add(llist_t *node, llist_t *head)
static void List_Create(llist_t *list)
#define List_First_Entry(ptr, type, member)
static void List_Delete(llist_t *node)
#define List_For_Each_Entry(pos, head, type, member)
static qbool List_Is_Empty(const llist_t *list)
char com_token[MAX_INPUTLINE]
qbool COM_ParseToken_Console(const char **datapointer)
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
#define dp_strlcpy(dst, src, dsize)
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
void Cvar_SetValueQuick(cvar_t *var, float value)
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLsizei const GLfloat * value
GLenum GLenum GLsizei count
GLsizeiptr const GLvoid * data
GLenum GLuint GLenum GLsizei const GLchar * buf
#define MAX_OSPATH
max length of a filesystem pathname
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
unsigned char * allocflags
size_t numrecordsperarray
memexpandablearray_array_t * arrays
struct mempool_s * parent
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
double Sys_Sleep(double time)
called to yield for a little bit so as not to hog cpu when paused or debugging
#define Thread_DestroyMutex(m)
qbool Thread_HasThreads(void)
#define Thread_CreateMutex()
#define Thread_LockMutex(m)
#define Thread_UnlockMutex(m)
static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l)
void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray)
qbool Mem_IsAllocated(mempool_t *pool, const void *data)
static void MemStats_f(cmd_state_t *cmd)
static void * Clump_AllocBlock(size_t size)
void _Mem_CheckSentinels(void *data, const char *filename, int fileline)
cvar_t developer_memorydebug
static void Clump_FreeBlock(void *base, size_t size)
static void * attempt_malloc(size_t size)
static void MemList_f(cmd_state_t *cmd)
cvar_t sys_memsize_physical
cvar_t sys_memsize_virtual
void * _Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment, const char *filename, int fileline)
void _Mem_EmptyPool(mempool_t *pool, const char *filename, int fileline)
char * _Mem_strdup(mempool_t *pool, const char *s, const char *filename, int fileline)
void Memory_Init_Commands(void)
void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record)
void _Mem_Free(void *data, const char *filename, int fileline)
void * Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l)
void _Mem_CheckSentinelsGlobal(const char *filename, int fileline)
unsigned int sentinel_seed
void Mem_PrintList(size_t minallocationsize)
cvar_t developer_memoryreportlargerthanmb
void Mem_PrintStats(void)
static mempool_t * poolchain
void * Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index)
mempool_t * _Mem_AllocPool(const char *name, unsigned flags, mempool_t *parent, const char *filename, int fileline)
void _Mem_FreePool(mempool_t **poolpointer, const char *filename, int fileline)
#define MEMHEADER_SENTINEL_FOR_ADDRESS(p)
void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l)
void Memory_Shutdown(void)
#define Mem_Alloc(pool, size)
#define Mem_AllocPool(name, flags, parent)
#define Mem_CheckSentinelsGlobal()