-
-
Save Erick194/cccab97eb7cad64fb338fa1048a4743d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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