shithub: choc

Download patch

ref: d5b2877a8e4d1c189cf77a8951f847f853327a7d
parent: 7305391e92dc8275758323d06b9b400602a59e72
author: Simon Howard <fraggle@gmail.com>
date: Fri Mar 24 14:59:03 EST 2006

Add a second implementation of the zone memory system which just uses 
malloc() and free() as a backend. This will be useful for running
dedicated servers (no need to allocate an entire heap).

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 435

--- /dev/null
+++ b/src/z_native.c
@@ -1,0 +1,361 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// $Id: z_native.c 435 2006-03-24 19:59:03Z fraggle $
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//	Zone Memory Allocation. Neat.
+//
+//	This is an implementation of the zone memory API which
+//	uses native calls to malloc() and free().
+//
+//-----------------------------------------------------------------------------
+
+static const char
+rcsid[] = "$Id: z_native.c 435 2006-03-24 19:59:03Z fraggle $";
+
+#include <stdlib.h>
+
+#include "z_zone.h"
+#include "i_system.h"
+#include "doomdef.h"
+
+#define ZONEID	0x1d4a11
+
+typedef struct memblock_s memblock_t;
+
+struct memblock_s
+{
+    int id; // = ZONEID
+    int tag;
+    void **user;
+    memblock_t *prev;
+    memblock_t *next;
+};
+
+// Linked list of allocated blocks for each tag type
+ 
+static memblock_t *allocated_blocks[PU_NUM_TAGS];
+
+// Add a block into the linked list for its type.
+
+static void Z_InsertBlock(memblock_t *block)
+{
+    block->prev = NULL;
+    block->next = allocated_blocks[block->tag];
+    allocated_blocks[block->tag] = block->next;
+    
+    if (block->next != NULL)
+    {
+        block->next->prev = block;
+    }
+}
+
+// Remove a block from its linked list.
+
+static void Z_RemoveBlock(memblock_t *block)
+{
+    // Unlink from list
+
+    if (block->prev == NULL)
+    {
+        // Start of list
+
+        allocated_blocks[block->tag] = block->next;
+    }
+    else
+    {
+        block->prev->next = block->next;
+    }
+
+    if (block->next != NULL)
+    {
+        block->next->prev = block->prev;
+    }
+}
+
+//
+// Z_Init
+//
+void Z_Init (void)
+{
+    memset(allocated_blocks, 0, sizeof(allocated_blocks));
+}
+
+
+//
+// Z_Free
+//
+void Z_Free (void* ptr)
+{
+    memblock_t*		block;
+
+    block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t));
+
+    if (block->id != ZONEID)
+        I_Error ("Z_Free: freed a pointer without ZONEID");
+		
+    if (block->tag != PU_FREE && block->user != NULL)
+    {
+        // clear the user's mark
+
+        *block->user = NULL;
+    }
+
+    Z_RemoveBlock(block);
+
+    // Free back to system
+
+    free(block);
+}
+
+
+
+//
+// Z_Malloc
+// You can pass a NULL user if the tag is < PU_PURGELEVEL.
+//
+
+void *Z_Malloc(int size, int tag, void *user)
+{
+    memblock_t *newblock;
+    unsigned char *data;
+    void *result;
+
+    if (tag < 0 || tag >= PU_NUM_TAGS || tag == PU_FREE)
+    {
+        I_Error("Z_Malloc: attempted to allocate a block with an invalid "
+                "tag: %i", tag);
+    }
+
+    if (user == NULL && tag >= PU_PURGELEVEL)
+        I_Error ("Z_Malloc: an owner is required for purgable blocks");
+    
+    newblock = (memblock_t *) malloc(sizeof(memblock_t) + size);
+    newblock->tag = tag;
+    
+    // Hook into the linked list for this tag type
+
+    newblock->id = ZONEID;
+    newblock->user = user;
+
+    Z_InsertBlock(newblock);
+
+    data = (unsigned char *) newblock;
+    result = data + sizeof(memblock_t);
+
+    if (user != NULL)
+    {
+        *newblock->user = result;
+    }
+    
+    return result;
+}
+
+
+
+//
+// Z_FreeTags
+//
+
+void Z_FreeTags(int lowtag, int hightag)
+{
+    int i;
+
+    for (i=lowtag; i<= hightag; ++i)
+    {
+        memblock_t *block;
+        memblock_t *next;
+
+        // Free all in this chain
+
+        for (block=allocated_blocks[i]; block != NULL; )
+        {
+            next = block->next;
+
+            // Free this block
+
+            if (block->user != NULL)
+            {
+                *block->user = NULL;
+            }
+            
+            free(block);
+
+            // Jump to the next in the chain
+
+            block = next;
+        }
+    }
+}
+
+
+
+//
+// Z_DumpHeap
+//
+void Z_DumpHeap(int lowtag, int	hightag)
+{
+    // broken
+
+#if 0
+    memblock_t*	block;
+	
+    printf ("zone size: %i  location: %p\n",
+	    mainzone->size,mainzone);
+    
+    printf ("tag range: %i to %i\n",
+	    lowtag, hightag);
+	
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+	if (block->tag >= lowtag && block->tag <= hightag)
+	    printf ("block:%p    size:%7i    user:%p    tag:%3i\n",
+		    block, block->size, block->user, block->tag);
+		
+	if (block->next == &mainzone->blocklist)
+	{
+	    // all blocks have been hit
+	    break;
+	}
+	
+	if ( (byte *)block + block->size != (byte *)block->next)
+	    printf ("ERROR: block size does not touch the next block\n");
+
+	if ( block->next->prev != block)
+	    printf ("ERROR: next block doesn't have proper back link\n");
+
+	if (block->tag == PU_FREE && block->next->tag == PU_FREE)
+	    printf ("ERROR: two consecutive free blocks\n");
+    }
+#endif
+}
+
+
+//
+// Z_FileDumpHeap
+//
+void Z_FileDumpHeap(FILE *f)
+{
+    // broken
+#if 0
+    memblock_t*	block;
+	
+    fprintf (f,"zone size: %i  location: %p\n",mainzone->size,mainzone);
+	
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+	fprintf (f,"block:%p    size:%7i    user:%p    tag:%3i\n",
+		 block, block->size, block->user, block->tag);
+		
+	if (block->next == &mainzone->blocklist)
+	{
+	    // all blocks have been hit
+	    break;
+	}
+	
+	if ( (byte *)block + block->size != (byte *)block->next)
+	    fprintf (f,"ERROR: block size does not touch the next block\n");
+
+	if ( block->next->prev != block)
+	    fprintf (f,"ERROR: next block doesn't have proper back link\n");
+
+	if (block->tag == PU_FREE && block->next->tag == PU_FREE)
+	    fprintf (f,"ERROR: two consecutive free blocks\n");
+    }
+#endif
+}
+
+
+
+//
+// Z_CheckHeap
+//
+void Z_CheckHeap (void)
+{
+    memblock_t *block;
+    memblock_t *prev;
+    int i;
+
+    // Check all chains
+
+    for (i=0; i<PU_NUM_TAGS; ++i)
+    {
+        prev = NULL;
+
+        for (block=allocated_blocks[i]; block != NULL; block = block->next)
+        {
+            if (block->prev != prev)
+            {
+                I_Error("Z_CheckHeap: Doubly-linked list corrupted!");
+            }
+            
+            if (block->id != ZONEID)
+            {
+                I_Error("Z_CheckHeap: Block without a ZONEID!");
+            }
+            
+            prev = block;
+        }
+    }
+}
+
+
+
+
+//
+// Z_ChangeTag
+//
+
+void Z_ChangeTag2(void *ptr, int tag, char *file, int line)
+{
+    memblock_t*	block;
+	
+    block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t));
+
+    if (block->id != ZONEID)
+        I_Error("%s:%i: Z_ChangeTag: block without a ZONEID!",
+                file, line);
+
+    if (tag >= PU_PURGELEVEL && block->user == NULL)
+        I_Error("%s:%i: Z_ChangeTag: an owner is required "
+                "for purgable blocks", file, line);
+
+    // Remove the block from its current list, and rehook it into
+    // its new list.
+
+    Z_RemoveBlock(block);
+    block->tag = tag;
+    Z_InsertBlock(block);
+}
+
+
+//
+// Z_FreeMemory
+//
+
+int Z_FreeMemory(void)
+{
+    // Limited by the system??
+
+    return -1;
+}
+