Skip to content

Instantly share code, notes, and snippets.

@Erick194

Erick194/PSXDOOM z_zone.c Secret

Created Jun 15, 2019
Embed
What would you like to do?
/* 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;
/*
========================
=
= Z_Init
=
========================
*/
extern unsigned int __bss;
extern unsigned int __bsslen;
#define bbs_start (__bss + __bsslen)
extern u_long __ramsize; // megabytes of RAM
extern u_long __stacksize; // kilobytes of stack
void Z_Init (void)//L80032014()
{
byte *mem;
int size;
mem = (byte *)((bbs_start + 3) & ~3);
size = (((__ramsize - __stacksize) - (((bbs_start + 3) & ~3) & 0x1FFFFFFF)) + 3) & ~3;
/* mars doesn't have a refzone */
mainzone = Z_InitZone (mem,size);
}
/*
========================
=
= Z_InitZone
=
========================
*/
memzone_t *Z_InitZone(byte *base, int size)//L8003206C()
{
memzone_t *zone;
zone = (memzone_t *)base;
zone->size = size;
zone->rover = &zone->blocklist;
zone->blocklist.size = size - (int)((byte *)&zone->blocklist - (byte *)zone);
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_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)//L800320A0()
{
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 + 3) & ~3; /* 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)
{
if (rover->tag < PU_PURGELEVEL)
{
/* 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 */
{
Z_DumpHeap(mainzone);
I_Error("Z_Malloc: failed allocation on %i", size);
}
continue;
}
/* */
/* free the rover block (adding the size to base) */
/* */
Z_Free((byte *)rover + sizeof(memblock_t)); /* 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 *)1; /* mark as in use, but unowned */
}
base->tag = tag;
base->id = ZONEID;
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_Alloc2
=
= You can pass a NULL user if the tag is < PU_PURGELEVEL
= Exclusive Psx Doom
========================
*/
void *Z_Alloc2(memzone_t *mainzone, int size, int tag, void *user)//L80032298()
{
int extra;
memblock_t *rover, *newblock, *base, *block;
/* */
/* scan through the block list looking for the first free block */
/* of sufficient size, throwing out any purgable blocks along the way */
/* */
base = &mainzone->blocklist;
for (block = mainzone->blocklist.next; block; block = base->next)
{
base = base->next;
}
size += sizeof(memblock_t); /* account for size of block header */
size = (size + 3) & ~3; /* phrase align everything */
while (base->user || base->size < size)
{
if (base->user)
rover = base;
else
{
/* hit an in use block, so move base past it */
rover = base->prev;
if (!rover)
I_Error("Z_Malloc: failed allocation on %i", size);
}
if (rover->user)
{
if (rover->tag < PU_PURGELEVEL)
{
/* hit an in use block, so move base past it */
base = rover->prev;
if (!base)
I_Error("Z_Malloc: failed allocation on %i", size);
continue;
}
/* */
/* free the rover block (adding the size to base) */
/* */
Z_Free((byte *)rover + sizeof(memblock_t)); /* mark as free */
}
if (base != rover)
{ /* merge with base */
rover->size += base->size;
rover->next = base->next;
if (base->next)
base->next->prev = rover;
base = rover;
}
}
/* */
/* found a block big enough */
/* */
extra = base->size - size;
if (extra > MINFRAGMENT)
{ /* there will be a free fragment after the allocated block */
newblock = base;
base = (memblock_t *)((byte *)base + extra);
base->prev = newblock;
base->next = newblock->next;
base->size = size;
if (base->next)
base->next->prev = base;
newblock->next = base;
newblock->size = extra;
newblock->user = NULL; // free block
newblock->tag = 0;
}
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 *)1; /* mark as in use, but unowned */
}
base->tag = tag;
base->id = ZONEID;
mainzone->rover = &mainzone->blocklist;
return (void *)((byte *)base + sizeof(memblock_t));
}
/*
========================
=
= Z_Free2
=
========================
*/
void Z_Free2(memzone_t *mainzone, void *ptr)//L800324A8()
{
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_FreeTags
=
========================
*/
void Z_FreeTags (memzone_t *mainzone, int tag)//L80032510()
{
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 & tag)
{
Z_Free(((byte *)block + sizeof(memblock_t)));
}
}
for (block = &mainzone->blocklist; block; block = next)
{
next = block->next; // get link before freeing
if (!block->user && next && !next->user)
{
block->size += next->size;
block->next = next->next;
if (next->next) // <- Final Doom, Doom GH, Eup Jap
next->next->prev = block;
}
}
mainzone->rover = &mainzone->blocklist;
}
/*
========================
=
= Z_CheckHeap
=
========================
*/
void Z_CheckHeap (memzone_t *mainzone)//L80032640()
{
memblock_t *checkblock;
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)//L80032708()
{
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)//L80032794()
{
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
=
========================
*/
void Z_DumpHeap(memzone_t *mainzone)//L800327D4()
{
#if 0
memblock_t *block;
printf("zone size: %i location: %p\n", mainzone->size, mainzone);
for (block = &mainzone->blocklist; block; block = block->next)
{
printf("block:%p size:%7i user:%p tag:%3i frame:%i\n",
block, block->size, block->user, block->tag, block->lockframe);
if (!block->next)
continue;
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");
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment