+// give malloc padding so we can't waste most of a page at the end
+#define MEMCLUMPSIZE (MEMWANTCLUMPSIZE - MEMWANTCLUMPSIZE/MEMUNIT/32 - 128)
+#define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
+#define MEMBITINTS (MEMBITS / 32)
+
+typedef struct memclump_s
+{
+ // contents of the clump
+ unsigned char block[MEMCLUMPSIZE];
+ // should always be MEMCLUMP_SENTINEL
+ unsigned int sentinel1;
+ // if a bit is on, it means that the MEMUNIT bytes it represents are
+ // allocated, otherwise free
+ unsigned int bits[MEMBITINTS];
+ // should always be MEMCLUMP_SENTINEL
+ unsigned int sentinel2;
+ // if this drops to 0, the clump is freed
+ size_t blocksinuse;
+ // largest block of memory available (this is reset to an optimistic
+ // number when anything is freed, and updated when alloc fails the clump)
+ size_t largestavailable;
+ // next clump in the chain
+ struct memclump_s *chain;
+}
+memclump_t;
+
+#if MEMCLUMPING == 2
+static memclump_t masterclump;
+#endif
+static memclump_t *clumpchain = NULL;
+#endif
+
+
+cvar_t developer_memory = {CF_CLIENT | CF_SERVER, "developer_memory", "0", "prints debugging information about memory allocations"};
+cvar_t developer_memorydebug = {CF_CLIENT | CF_SERVER, "developer_memorydebug", "0", "enables memory corruption checks (very slow)"};
+cvar_t developer_memoryreportlargerthanmb = {CF_CLIENT | CF_SERVER, "developer_memorylargerthanmb", "16", "prints debugging information about memory allocations over this size"};
+cvar_t sys_memsize_physical = {CF_CLIENT | CF_SERVER | CF_READONLY, "sys_memsize_physical", "", "physical memory size in MB (or empty if unknown)"};
+cvar_t sys_memsize_virtual = {CF_CLIENT | CF_SERVER | CF_READONLY, "sys_memsize_virtual", "", "virtual memory size in MB (or empty if unknown)"};
+
+static mempool_t *poolchain = NULL;
+
+void Mem_PrintStats(void);
+void Mem_PrintList(size_t minallocationsize);
+
+#if FILE_BACKED_MALLOC
+#include <stdlib.h>
+#include <sys/mman.h>
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+typedef struct mmap_data_s
+{
+ size_t len;
+}
+mmap_data_t;
+static void *mmap_malloc(size_t size)
+{
+ char vabuf[MAX_OSPATH + 1];
+ char *tmpdir = getenv("TEMP");
+ mmap_data_t *data;
+ int fd;
+ size += sizeof(mmap_data_t); // waste block
+ dpsnprintf(vabuf, sizeof(vabuf), "%s/darkplaces.XXXXXX", tmpdir ? tmpdir : "/tmp");
+ fd = mkstemp(vabuf);
+ if(fd < 0)