]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - zone.c
added developer_memory cvar (default off) to decide whether to print memory debugging...
[xonotic/darkplaces.git] / zone.c
diff --git a/zone.c b/zone.c
index db9952ffecd58eac20c4facc10208841e1874c2f..196324375527c9e48170c890c0180366323116e5 100644 (file)
--- a/zone.c
+++ b/zone.c
@@ -21,9 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
+cvar_t developer_memory = {0, "developer_memory", "0"};
+
 mempool_t *poolchain = NULL;
 
-void *_Mem_Alloc(mempool_t *pool, int size, char *filename, int fileline)
+void *_Mem_Alloc(mempool_t *pool, int size, const char *filename, int fileline)
 {
 #if MEMCLUMPING
        int i, j, k, needed, endbit, largest;
@@ -34,7 +36,8 @@ void *_Mem_Alloc(mempool_t *pool, int size, char *filename, int fileline)
                return NULL;
        if (pool == NULL)
                Sys_Error("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline);
-       Con_DPrintf("Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, size);
+       if (developer.integer && developer_memory.integer)
+               Con_Printf("Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, size);
        pool->totalsize += size;
 #if MEMCLUMPING
        if (size < 4096)
@@ -110,91 +113,95 @@ choseclump:
        // we have to use only a single byte for this sentinel, because it may not be aligned, and some platforms can't use unaligned accesses
        *((qbyte *) mem + sizeof(memheader_t) + mem->size) = MEMHEADER_SENTINEL2;
        // append to head of list
-       mem->chain = pool->chain;
+       mem->next = pool->chain;
+       mem->prev = NULL;
        pool->chain = mem;
+       if (mem->next)
+               mem->next->prev = mem;
        memset((void *)((qbyte *) mem + sizeof(memheader_t)), 0, mem->size);
        return (void *)((qbyte *) mem + sizeof(memheader_t));
 }
 
-void _Mem_Free(void *data, char *filename, int fileline)
+void _Mem_Free(void *data, const char *filename, int fileline)
 {
 #if MEMCLUMPING
        int i, firstblock, endblock;
        memclump_t *clump, **clumpchainpointer;
 #endif
-       memheader_t *mem, **memchainpointer;
+       memheader_t *mem;
        mempool_t *pool;
        if (data == NULL)
                Sys_Error("Mem_Free: data == NULL (called at %s:%i)", filename, fileline);
 
-
        mem = (memheader_t *)((qbyte *) data - sizeof(memheader_t));
        if (mem->sentinel1 != MEMHEADER_SENTINEL1)
                Sys_Error("Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
        if (*((qbyte *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2)
                Sys_Error("Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
        pool = mem->pool;
-       Con_DPrintf("Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, mem->size);
-       for (memchainpointer = &pool->chain;*memchainpointer;memchainpointer = &(*memchainpointer)->chain)
+       if (developer.integer && developer_memory.integer)
+               Con_Printf("Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, mem->size);
+       // 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->prev)
+               mem->prev->next = mem->next;
+       else
+               pool->chain = mem->next;
+       if (mem->next)
+               mem->next->prev = mem->prev;
+       // memheader has been unlinked, do the actual free now
+       pool->totalsize -= mem->size;
+#if MEMCLUMPING
+       if ((clump = mem->clump))
        {
-               if (*memchainpointer == mem)
+               if (clump->sentinel1 != MEMCLUMP_SENTINEL)
+                       Sys_Error("Mem_Free: trashed clump sentinel 1 (free at %s:%i)", filename, fileline);
+               if (clump->sentinel2 != MEMCLUMP_SENTINEL)
+                       Sys_Error("Mem_Free: trashed clump sentinel 2 (free at %s:%i)", filename, fileline);
+               firstblock = ((qbyte *) mem - (qbyte *) clump->block);
+               if (firstblock & (MEMUNIT - 1))
+                       Sys_Error("Mem_Free: address not valid in clump (free at %s:%i)", filename, fileline);
+               firstblock /= MEMUNIT;
+               endblock = firstblock + ((sizeof(memheader_t) + mem->size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT);
+               clump->blocksinuse -= endblock - firstblock;
+               // could use &, but we know the bit is set
+               for (i = firstblock;i < endblock;i++)
+                       clump->bits[i >> 5] -= (1 << (i & 31));
+               if (clump->blocksinuse <= 0)
                {
-                       *memchainpointer = mem->chain;
-                       pool->totalsize -= mem->size;
-#if MEMCLUMPING
-                       if ((clump = mem->clump))
+                       // unlink from chain
+                       for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
                        {
-                               if (clump->sentinel1 != MEMCLUMP_SENTINEL)
-                                       Sys_Error("Mem_Free: trashed clump sentinel 1 (free at %s:%i)", filename, fileline);
-                               if (clump->sentinel2 != MEMCLUMP_SENTINEL)
-                                       Sys_Error("Mem_Free: trashed clump sentinel 2 (free at %s:%i)", filename, fileline);
-                               firstblock = ((qbyte *) mem - (qbyte *) clump->block);
-                               if (firstblock & (MEMUNIT - 1))
-                                       Sys_Error("Mem_Free: address not valid in clump (free at %s:%i)", filename, fileline);
-                               firstblock /= MEMUNIT;
-                               endblock = firstblock + ((sizeof(memheader_t) + mem->size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT);
-                               clump->blocksinuse -= endblock - firstblock;
-                               // could use &, but we know the bit is set
-                               for (i = firstblock;i < endblock;i++)
-                                       clump->bits[i >> 5] -= (1 << (i & 31));
-                               if (clump->blocksinuse <= 0)
-                               {
-                                       // unlink from chain
-                                       for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
-                                       {
-                                               if (*clumpchainpointer == clump)
-                                               {
-                                                       *clumpchainpointer = clump->chain;
-                                                       break;
-                                               }
-                                       }
-                                       pool->realsize -= sizeof(memclump_t);
-                                       memset(clump, 0xBF, sizeof(memclump_t));
-                                       free(clump);
-                               }
-                               else
+                               if (*clumpchainpointer == clump)
                                {
-                                       // clump still has some allocations
-                                       // force re-check of largest available space on next alloc
-                                       clump->largestavailable = MEMBITS - clump->blocksinuse;
+                                       *clumpchainpointer = clump->chain;
+                                       break;
                                }
                        }
-                       else
-                       {
+                       pool->realsize -= sizeof(memclump_t);
+                       memset(clump, 0xBF, sizeof(memclump_t));
+                       free(clump);
+               }
+               else
+               {
+                       // clump still has some allocations
+                       // force re-check of largest available space on next alloc
+                       clump->largestavailable = MEMBITS - clump->blocksinuse;
+               }
+       }
+       else
+       {
 #endif
-                               pool->realsize -= sizeof(memheader_t) + mem->size + sizeof(int);
-                               memset(mem, 0xBF, sizeof(memheader_t) + mem->size + sizeof(int));
-                               free(mem);
+               pool->realsize -= sizeof(memheader_t) + mem->size + sizeof(int);
+               memset(mem, 0xBF, sizeof(memheader_t) + mem->size + sizeof(int));
+               free(mem);
 #if MEMCLUMPING
-                       }
-#endif
-                       return;
-               }
        }
-       Sys_Error("Mem_Free: not allocated (free at %s:%i)", filename, fileline);
+#endif
 }
 
-mempool_t *_Mem_AllocPool(char *name, char *filename, int fileline)
+mempool_t *_Mem_AllocPool(const char *name, const char *filename, int fileline)
 {
        mempool_t *pool;
        pool = malloc(sizeof(mempool_t));
@@ -214,7 +221,7 @@ mempool_t *_Mem_AllocPool(char *name, char *filename, int fileline)
        return pool;
 }
 
-void _Mem_FreePool(mempool_t **pool, char *filename, int fileline)
+void _Mem_FreePool(mempool_t **pool, const char *filename, int fileline)
 {
        mempool_t **chainaddress;
        if (*pool)
@@ -240,7 +247,7 @@ void _Mem_FreePool(mempool_t **pool, char *filename, int fileline)
        }
 }
 
-void _Mem_EmptyPool(mempool_t *pool, char *filename, int fileline)
+void _Mem_EmptyPool(mempool_t *pool, const char *filename, int fileline)
 {
        if (pool == NULL)
                Sys_Error("Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline);
@@ -254,7 +261,7 @@ void _Mem_EmptyPool(mempool_t *pool, char *filename, int fileline)
                Mem_Free((void *)((qbyte *) pool->chain + sizeof(memheader_t)));
 }
 
-void _Mem_CheckSentinels(void *data, char *filename, int fileline)
+void _Mem_CheckSentinels(void *data, const char *filename, int fileline)
 {
        memheader_t *mem;
 
@@ -269,7 +276,7 @@ void _Mem_CheckSentinels(void *data, char *filename, int fileline)
 }
 
 #if MEMCLUMPING
-static void _Mem_CheckClumpSentinels(memclump_t *clump, char *filename, int fileline)
+static void _Mem_CheckClumpSentinels(memclump_t *clump, const char *filename, int fileline)
 {
        // this isn't really very useful
        if (clump->sentinel1 != MEMCLUMP_SENTINEL)
@@ -279,7 +286,7 @@ static void _Mem_CheckClumpSentinels(memclump_t *clump, char *filename, int file
 }
 #endif
 
-void _Mem_CheckSentinelsGlobal(char *filename, int fileline)
+void _Mem_CheckSentinelsGlobal(const char *filename, int fileline)
 {
        memheader_t *mem;
 #if MEMCLUMPING
@@ -294,7 +301,7 @@ void _Mem_CheckSentinelsGlobal(char *filename, int fileline)
                        Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
        }
        for (pool = poolchain;pool;pool = pool->next)
-               for (mem = pool->chain;mem;mem = mem->chain)
+               for (mem = pool->chain;mem;mem = mem->next)
                        _Mem_CheckSentinels((void *)((qbyte *) mem + sizeof(memheader_t)), filename, fileline);
 #if MEMCLUMPING
        for (pool = poolchain;pool;pool = pool->next)
@@ -328,7 +335,7 @@ void Mem_PrintStats(void)
        {
                Con_Printf("%i bytes (%.3fMB) of temporary memory still allocated (Leak!)\n", tempmempool->totalsize, tempmempool->totalsize / 1048576.0);
                Con_Printf("listing temporary memory allocations:\n");
-               for (mem = tempmempool->chain;mem;mem = mem->chain)
+               for (mem = tempmempool->chain;mem;mem = mem->next)
                        Con_Printf("%10i bytes allocated at %s:%i\n", mem->size, mem->filename, mem->fileline);
        }
 }
@@ -348,7 +355,7 @@ void Mem_PrintList(int listallocations)
                        Con_Printf("%6ik (%6ik actual) %s\n", (pool->totalsize + 1023) / 1024, (pool->realsize + 1023) / 1024, pool->name);
                pool->lastchecksize = pool->totalsize;
                if (listallocations)
-                       for (mem = pool->chain;mem;mem = mem->chain)
+                       for (mem = pool->chain;mem;mem = mem->next)
                                Con_Printf("%10i bytes allocated at %s:%i\n", mem->size, mem->filename, mem->fileline);
        }
 }
@@ -399,5 +406,6 @@ void Memory_Init_Commands (void)
 {
        Cmd_AddCommand ("memstats", MemStats_f);
        Cmd_AddCommand ("memlist", MemList_f);
+       Cvar_RegisterVariable (&developer_memory);
 }