]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - zone.c
added cl_noplayershadow cvar to allow disabling player shadow
[xonotic/darkplaces.git] / zone.c
diff --git a/zone.c b/zone.c
index fb485f84a918d9a11cfbf53838078651fcc85235..196324375527c9e48170c890c0180366323116e5 100644 (file)
--- a/zone.c
+++ b/zone.c
@@ -21,19 +21,25 @@ 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;
        memclump_t *clump, **clumpchainpointer;
+#endif
        memheader_t *mem;
        if (size <= 0)
                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)
        {
                // clumping
@@ -90,12 +96,15 @@ choseclump:
        else
        {
                // big allocations are not clumped
+#endif
                pool->realsize += sizeof(memheader_t) + size + sizeof(int);
                mem = malloc(sizeof(memheader_t) + size + sizeof(int));
                if (mem == NULL)
                        Sys_Error("Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline);
+#if MEMCLUMPING
                mem->clump = NULL;
        }
+#endif
        mem->filename = filename;
        mem->fileline = fileline;
        mem->size = size;
@@ -104,110 +113,123 @@ 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;
-       memheader_t *mem, **memchainpointer;
+#endif
+       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 ((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)
+                               if (*clumpchainpointer == clump)
                                {
-                                       // 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);
+                                       *clumpchainpointer = clump->chain;
+                                       break;
                                }
-                               else
-                               {
-                                       // clump still has some allocations
-                                       // force re-check of largest available space on next alloc
-                                       clump->largestavailable = MEMBITS - clump->blocksinuse;
-                               }
-                       }
-                       else
-                       {
-                               pool->realsize -= sizeof(memheader_t) + mem->size + sizeof(int);
-                               memset(mem, 0xBF, sizeof(memheader_t) + mem->size + sizeof(int));
-                               free(mem);
                        }
-                       return;
+                       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;
                }
        }
-       Sys_Error("Mem_Free: not allocated (free at %s:%i)", filename, fileline);
+       else
+       {
+#endif
+               pool->realsize -= sizeof(memheader_t) + mem->size + sizeof(int);
+               memset(mem, 0xBF, sizeof(memheader_t) + mem->size + sizeof(int));
+               free(mem);
+#if MEMCLUMPING
+       }
+#endif
 }
 
-mempool_t *_Mem_AllocPool(char *name, char *filename, int fileline)
+mempool_t *_Mem_AllocPool(const char *name, const char *filename, int fileline)
 {
-//     int i;
        mempool_t *pool;
        pool = malloc(sizeof(mempool_t));
        if (pool == NULL)
                Sys_Error("Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline);
        memset(pool, 0, sizeof(mempool_t));
+       pool->sentinel1 = MEMHEADER_SENTINEL1;
+       pool->sentinel2 = MEMHEADER_SENTINEL1;
+       pool->filename = filename;
+       pool->fileline = fileline;
        pool->chain = NULL;
        pool->totalsize = 0;
        pool->realsize = sizeof(mempool_t);
        strcpy(pool->name, name);
-//     for (i = 0;i < (POOLNAMESIZE - 1) && name[i];i++)
-//             pool->name[i] = name[i];
-//     for (i = 0;i < POOLNAMESIZE;i++)
-//             pool->name[i] = 0;
        pool->next = poolchain;
        poolchain = pool;
        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)
        {
+               if ((*pool)->sentinel1 != MEMHEADER_SENTINEL1)
+                       Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", (*pool)->filename, (*pool)->fileline, filename, fileline);
+               if ((*pool)->sentinel2 != MEMHEADER_SENTINEL1)
+                       Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", (*pool)->filename, (*pool)->fileline, filename, fileline);
                // unlink pool from chain
                for (chainaddress = &poolchain;*chainaddress && *chainaddress != *pool;chainaddress = &((*chainaddress)->next));
                if (*chainaddress != *pool)
@@ -225,17 +247,21 @@ 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);
+       if (pool->sentinel1 != MEMHEADER_SENTINEL1)
+               Sys_Error("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+       if (pool->sentinel2 != MEMHEADER_SENTINEL1)
+               Sys_Error("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
 
        // free memory owned by the pool
        while (pool->chain)
                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;
 
@@ -249,7 +275,8 @@ void _Mem_CheckSentinels(void *data, char *filename, int fileline)
                Sys_Error("Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline);
 }
 
-static void _Mem_CheckClumpSentinels(memclump_t *clump, char *filename, int fileline)
+#if MEMCLUMPING
+static void _Mem_CheckClumpSentinels(memclump_t *clump, const char *filename, int fileline)
 {
        // this isn't really very useful
        if (clump->sentinel1 != MEMCLUMP_SENTINEL)
@@ -257,19 +284,30 @@ static void _Mem_CheckClumpSentinels(memclump_t *clump, char *filename, int file
        if (clump->sentinel2 != MEMCLUMP_SENTINEL)
                Sys_Error("Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)", filename, fileline);
 }
+#endif
 
-void _Mem_CheckSentinelsGlobal(char *filename, int fileline)
+void _Mem_CheckSentinelsGlobal(const char *filename, int fileline)
 {
        memheader_t *mem;
+#if MEMCLUMPING
        memclump_t *clump;
+#endif
        mempool_t *pool;
        for (pool = poolchain;pool;pool = pool->next)
        {
-               for (mem = pool->chain;mem;mem = mem->chain)
+               if (pool->sentinel1 != MEMHEADER_SENTINEL1)
+                       Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+               if (pool->sentinel2 != MEMHEADER_SENTINEL1)
+                       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->next)
                        _Mem_CheckSentinels((void *)((qbyte *) mem + sizeof(memheader_t)), filename, fileline);
+#if MEMCLUMPING
+       for (pool = poolchain;pool;pool = pool->next)
                for (clump = pool->clumpchain;clump;clump = clump->chain)
                        _Mem_CheckClumpSentinels(clump, filename, fileline);
-       }
+#endif
 }
 
 // used for temporary memory allocations around the engine, not for longterm
@@ -297,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);
        }
 }
@@ -317,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);
        }
 }
@@ -368,5 +406,6 @@ void Memory_Init_Commands (void)
 {
        Cmd_AddCommand ("memstats", MemStats_f);
        Cmd_AddCommand ("memlist", MemList_f);
+       Cvar_RegisterVariable (&developer_memory);
 }