Source to src/z_zone.c


Enter a symbol's name here to quickly find it.

/* Z_zone.c */

#include "doomdef.h"

/* 
============================================================================== 
 
						ZONE MEMORY ALLOCATION 
 
There is never any space between memblocks, and there will never be two
contiguous free memblocks.

The rover can be left pointing at a non-empty block

It is of no value to free a cachable block, because it will get overwritten
automatically if needed

============================================================================== 
*/ 
 
memzone_t	*mainzone;
memzone_t	*refzone;

 
/*
========================
=
= Z_InitZone
=
========================
*/

memzone_t *Z_InitZone (byte *base, int size)
{
	memzone_t *zone;
	
	zone = (memzone_t *)base;
	
	zone->size = size;
	zone->rover = &zone->blocklist;
	zone->blocklist.size = size - 8;
	zone->blocklist.user = NULL;
	zone->blocklist.tag = 0;
	zone->blocklist.id = ZONEID;
	zone->blocklist.next = NULL;
	zone->blocklist.prev = NULL;
	zone->blocklist.lockframe = -1;

	return zone;
}

/*
========================
=
= Z_Init
=
========================
*/

void Z_Init (void)
{
	byte	*mem;
	int		size;

	mem = I_ZoneBase (&size);
	
#ifdef MARS
/* mars doesn't have a refzone */
	mainzone = Z_InitZone (mem,size);
#else
	mainzone = Z_InitZone (mem,0x80000);
	refzone = Z_InitZone (mem+0x80000,size-0x80000);
#endif
}


/*
========================
=
= Z_Free2
=
========================
*/

void Z_Free2 (memzone_t *mainzone, 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->user > (void **)0x100)	/* smaller values are not pointers */
		*block->user = 0;		/* clear the user's mark */
	block->user = NULL;	/* mark as free */
	block->tag = 0;
	block->id = 0;
}

 
/*
========================
=
= Z_Malloc2
=
= You can pass a NULL user if the tag is < PU_PURGELEVEL
========================
*/

#define MINFRAGMENT	64

void *Z_Malloc2 (memzone_t *mainzone, int size, int tag, void *user)
{
	int		extra;
	memblock_t	*start, *rover, *new, *base;

#if 0
Z_CheckHeap (mainzone);	/* DEBUG */
#endif

/* */
/* scan through the block list looking for the first free block */
/* of sufficient size, throwing out any purgable blocks along the way */
/* */
	size += sizeof(memblock_t);	/* account for size of block header */
	size = (size+7)&~7;			/* phrase align everything */
	
	
	start = base = mainzone->rover;
	
	while (base->user || base->size < size)
	{
		if (base->user)
			rover = base;
		else
			rover = base->next;
			
		if (!rover)
			goto backtostart;
		
		if (rover->user)
		{
		/* hit an in use block, so move base past it */
			base = rover->next;
			if (!base)
			{
backtostart:
				base = &mainzone->blocklist;
			}
			
			if (base == start)	/* scaned all the way around the list */
				I_Error ("Z_Malloc: failed on %i",size);
			continue;
		}
		
	/* */
	/* free the rover block (adding the size to base) */
	/*		 */
		rover->id = 0;
		rover->user = NULL;		/* mark as free */
		
		if (base != rover)
		{	/* merge with base */
			base->size += rover->size;
			base->next = rover->next;
			if (rover->next)
				rover->next->prev = base;
		}
	}
	
/* */
/* found a block big enough */
/* */
	extra = base->size - size;
	if (extra >  MINFRAGMENT)
	{	/* there will be a free fragment after the allocated block */
		new = (memblock_t *) ((byte *)base + size );
		new->size = extra;
		new->user = NULL;		/* free block */
		new->tag = 0;
		new->prev = base;
		new->next = base->next;
		if (new->next)
			new->next->prev = new;
		base->next = new;
		base->size = size;
	}
	
	if (user)
	{
		base->user = user;			/* mark as an in use block */
		*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
	}
	else
	{
		if (tag >= PU_PURGELEVEL)
			I_Error ("Z_Malloc: an owner is required for purgable blocks");
		base->user = (void *)2;		/* mark as in use, but unowned	 */
	}
	base->tag = tag;
	base->id = ZONEID;
	base->lockframe = -1;
		
	mainzone->rover = base->next;	/* next allocation will start looking here */
	if (!mainzone->rover)
		mainzone->rover = &mainzone->blocklist;
		
	return (void *) ((byte *)base + sizeof(memblock_t));
}


/*
========================
=
= Z_FreeTags
=
========================
*/

void Z_FreeTags (memzone_t *mainzone)
{
	memblock_t	*block, *next;
	
	for (block = &mainzone->blocklist ; block ; block = next)
	{
		next = block->next;		/* get link before freeing */
		if (!block->user)
			continue;			/* free block */
		if (block->tag == PU_LEVEL || block->tag == PU_LEVSPEC)
			Z_Free2 (mainzone, (byte *)block+sizeof(memblock_t));
	}
}


/*
========================
=
= Z_CheckHeap
=
========================
*/

memblock_t	*checkblock;

void Z_CheckHeap (memzone_t *mainzone)
{
	
	for (checkblock = &mainzone->blocklist ; checkblock; checkblock = checkblock->next)
	{
		if (!checkblock->next)
		{
			if ((byte *)checkblock + checkblock->size - (byte *)mainzone
			!= mainzone->size)
				I_Error ("Z_CheckHeap: zone size changed\n");
			continue;
		}
		
		if ( (byte *)checkblock + checkblock->size != (byte *)checkblock->next)
			I_Error ("Z_CheckHeap: block size does not touch the next block\n");
		if ( checkblock->next->prev != checkblock)
			I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
	}
}


/*
========================
=
= Z_ChangeTag
=
========================
*/

void Z_ChangeTag (void *ptr, int tag)
{
	memblock_t	*block;
	
	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
	if (block->id != ZONEID)
		I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
	if (tag >= PU_PURGELEVEL && (int)block->user < 0x100)
		I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
	block->tag = tag;
}


/*
========================
=
= Z_FreeMemory
=
========================
*/

int Z_FreeMemory (memzone_t *mainzone)
{
	memblock_t	*block;
	int			free;
	
	free = 0;
	for (block = &mainzone->blocklist ; block ; block = block->next)
		if (!block->user)
			free += block->size;
	return free;
}

/*
========================
=
= Z_DumpHeap
=
========================
*/

#ifdef NeXT