]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - zone.c
crazy feature: -DFILE_BASED_MALLOC=1
[xonotic/darkplaces.git] / zone.c
diff --git a/zone.c b/zone.c
index e90df30bff1283333b035af9e8cea2f007c527b4..85a3b2199776b654539afc10499e9b08889fc7ff 100644 (file)
--- a/zone.c
+++ b/zone.c
@@ -20,9 +20,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // Z_zone.c
 
 #include "quakedef.h"
+#include "thread.h"
 
 #ifdef WIN32
 #include <windows.h>
+#include <winbase.h>
 #else
 #include <unistd.h>
 #endif
@@ -36,16 +38,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 unsigned int sentinel_seed;
 
 qboolean mem_bigendian = false;
+void *mem_mutex = NULL;
+
+// divVerent: enables file backed malloc using mmap to conserve swap space (instead of malloc)
+#ifndef FILE_BACKED_MALLOC
+# define FILE_BACKED_MALLOC 0
+#endif
 
 // LordHavoc: enables our own low-level allocator (instead of malloc)
-#define MEMCLUMPING 0
-#define MEMCLUMPING_FREECLUMPS 0
+#ifndef MEMCLUMPING
+# define MEMCLUMPING 0
+#endif
+#ifndef MEMCLUMPING_FREECLUMPS
+# define MEMCLUMPING_FREECLUMPS 0
+#endif
 
 #if MEMCLUMPING
 // smallest unit we care about is this many bytes
 #define MEMUNIT 128
 // try to do 32MB clumps, but overhead eats into this
-#define MEMWANTCLUMPSIZE (1<<27)
+#ifndef MEMWANTCLUMPSIZE
+# define MEMWANTCLUMPSIZE (1<<27)
+#endif
 // 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)
@@ -89,6 +103,49 @@ 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>
+typedef struct mmap_data_s
+{
+       size_t len;
+}
+mmap_data_t;
+#define MMAP_PAGE_SIZE max(sizeof(mmap_data_t), (size_t)sysconf(_SC_PAGE_SIZE))
+static void *mmap_malloc(size_t size)
+{
+       char vabuf[MAX_OSPATH + 1];
+       char *tmpdir = getenv("TEMP");
+       unsigned char *data;
+       int fd;
+       size += MMAP_PAGE_SIZE; // waste block
+       size += MMAP_PAGE_SIZE - 1; // also, waste up to this amount for management info
+       size -= (size % MMAP_PAGE_SIZE); // round down
+       dpsnprintf(vabuf, sizeof(vabuf), "%s/darkplaces.XXXXXX", tmpdir ? tmpdir : "/tmp");
+       fd = mkstemp(vabuf);
+       if(fd < 0)
+               return NULL;
+       ftruncate(fd, size);
+       data = (unsigned char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
+       close(fd);
+       unlink(vabuf);
+       if(!data)
+               return NULL;
+       ((mmap_data_t *) data)->len = size;
+       return (void *) (data + MMAP_PAGE_SIZE);
+}
+static void mmap_free(void *mem)
+{
+       unsigned char *data;
+       if(!mem)
+               return;
+       data = (unsigned char *) mem - MMAP_PAGE_SIZE;
+       munmap(data, ((mmap_data_t *) data)->len);
+}
+#define malloc mmap_malloc
+#define free mmap_free
+#endif
+
 #if MEMCLUMPING != 2
 // some platforms have a malloc that returns NULL but succeeds later
 // (Windows growing its swapfile for example)
@@ -329,6 +386,8 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment,
        }
        if (pool == NULL)
                Sys_Error("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline);
+       if (mem_mutex)
+               Thread_LockMutex(mem_mutex);
        if (developer_memory.integer)
                Con_DPrintf("Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, (int)size);
        //if (developer.integer > 0 && developer_memorydebug.integer)
@@ -366,6 +425,9 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment,
        if (mem->next)
                mem->next->prev = mem;
 
+       if (mem_mutex)
+               Thread_UnlockMutex(mem_mutex);
+
        // copy the shared portion in the case of a realloc, then memset the rest
        sharedsize = 0;
        remainsize = size;
@@ -404,6 +466,8 @@ static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
        // unlink memheader from doubly linked list
        if ((mem->prev ? mem->prev->next != mem : pool->chain != mem) || (mem->next && mem->next->prev != mem))
                Sys_Error("Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline);
+       if (mem_mutex)
+               Thread_LockMutex(mem_mutex);
        if (mem->prev)
                mem->prev->next = mem->next;
        else
@@ -416,6 +480,8 @@ static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
        pool->totalsize -= size;
        pool->realsize -= realsize;
        Clump_FreeBlock(mem->baseaddress, realsize);
+       if (mem_mutex)
+               Thread_UnlockMutex(mem_mutex);
 }
 
 void _Mem_Free(void *data, const char *filename, int fileline)
@@ -633,7 +699,7 @@ void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l)
 void *Mem_ExpandableArray_AllocRecordAtIndex(memexpandablearray_t *l, size_t index)
 {
        size_t j;
-       if (index == l->numarrays)
+       if (index >= l->numarrays)
        {
                if (l->numarrays == l->maxarrays)
                {
@@ -812,7 +878,7 @@ void Mem_PrintList(size_t minallocationsize)
        }
 }
 
-void MemList_f(void)
+static void MemList_f(void)
 {
        switch(Cmd_Argc())
        {
@@ -830,8 +896,7 @@ void MemList_f(void)
        }
 }
 
-extern void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal);
-void MemStats_f(void)
+static void MemStats_f(void)
 {
        Mem_CheckSentinelsGlobal();
        R_TextureStats_Print(false, false, true);
@@ -843,8 +908,10 @@ void MemStats_f(void)
 char* Mem_strdup (mempool_t *pool, const char* s)
 {
        char* p;
-       size_t sz = strlen (s) + 1;
-       if (s == NULL) return NULL;
+       size_t sz;
+       if (s == NULL)
+               return NULL;
+       sz = strlen (s) + 1;
        p = (char*)Mem_Alloc (pool, sz);
        strlcpy (p, s, sz);
        return p;
@@ -865,12 +932,19 @@ void Memory_Init (void)
        poolchain = NULL;
        tempmempool = Mem_AllocPool("Temporary Memory", POOLFLAG_TEMP, NULL);
        zonemempool = Mem_AllocPool("Zone", 0, NULL);
+
+       if (Thread_HasThreads())
+               mem_mutex = Thread_CreateMutex();
 }
 
 void Memory_Shutdown (void)
 {
 //     Mem_FreePool (&zonemempool);
 //     Mem_FreePool (&tempmempool);
+
+       if (mem_mutex)
+               Thread_DestroyMutex(mem_mutex);
+       mem_mutex = NULL;
 }
 
 void Memory_Init_Commands (void)
@@ -883,18 +957,31 @@ void Memory_Init_Commands (void)
        Cvar_RegisterVariable (&sys_memsize_virtual);
 
 #if defined(WIN32)
+#ifdef _WIN64
        {
                MEMORYSTATUSEX status;
                // first guess
-               Cvar_SetQuick(&sys_memsize_virtual, (sizeof(void*) == 4) ? 2048 : 8388608);
+               Cvar_SetValueQuick(&sys_memsize_virtual, 8388608);
                // then improve
                status.dwLength = sizeof(status);
-               if(!GlobalMemoryStatusEx(&status))
+               if(GlobalMemoryStatusEx(&status))
                {
                        Cvar_SetValueQuick(&sys_memsize_physical, status.ullTotalPhys / 1048576.0);
                        Cvar_SetValueQuick(&sys_memsize_virtual, min(sys_memsize_virtual.value, status.ullTotalVirtual / 1048576.0));
                }
        }
+#else
+       {
+               MEMORYSTATUS status;
+               // first guess
+               Cvar_SetValueQuick(&sys_memsize_virtual, 2048);
+               // then improve
+               status.dwLength = sizeof(status);
+               GlobalMemoryStatus(&status);
+               Cvar_SetValueQuick(&sys_memsize_physical, status.dwTotalPhys / 1048576.0);
+               Cvar_SetValueQuick(&sys_memsize_virtual, min(sys_memsize_virtual.value, status.dwTotalVirtual / 1048576.0));
+       }
+#endif
 #else
        {
                // first guess