Support multiple zones in Z_Malloc and add user stack leftover

lumpinfo is now allocated in Z_Malloc because it's needed for some
larger WADs.

More heap is needed to compensate and to support larger WADs fully, so
the unused part of the user stack is added as a second zone.

This makes at least the start of the DOOM Ultimate WAD playable.
This commit is contained in:
Lephenixnoir 2021-07-29 16:45:26 +02:00
parent e18b08d5e4
commit b9c676ea4e
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 202 additions and 95 deletions

View File

@ -368,6 +368,20 @@ void D_DoomMain()
// int repisode=1;
// int rmap=1;
/* CGDOOM: Z_Init is executed early because we rely on the larger heap to
allocate the lump cache and lump info; normal heap isn't enough for WADs
larger than the shareware WAD */
Z_Init ();
for (int i = 0; true; i++)
{
int zone_size;
void *zone_base = I_ZoneBase(&zone_size, i);
if (zone_base == NULL)
break;
Z_AddZone (zone_base, zone_size);
}
ok_wad=W_InitMultipleFiles();
if(W_CheckNumForName("MAP01")!=-1)
@ -404,7 +418,7 @@ void D_DoomMain()
#endif
}
if(maxepisode>1)
if(maxepisode>1) {}
#if 0 //TODO !
do
{
@ -455,7 +469,7 @@ void D_DoomMain()
//printf ("V_Init: Allocate screens\n");
V_Init ();
//printf ("Z_Init: Init zone memory allocation daemon \n");
Z_Init ();
//Z_Init ();
//printf ("W_Init: Init WADfiles\n");
W_InitMultipleFiles ();

View File

@ -57,12 +57,24 @@ int I_GetHeapSize (void)
return RAM_I_Zone_SIZE;
}
byte* I_ZoneBase (int* size)
byte* I_ZoneBase (int* size, int i)
{
*size = RAM_I_Zone_SIZE;
mb_mainzone = (byte *) SystemStack;
ASSERT(RAM_I_Zone_SIZE <= SYSTEM_STACK_SIZE);
return mb_mainzone;
if (i == 0)
{
/* System stack (~500 kiB) */
*size = RAM_I_Zone_SIZE;
mb_mainzone = (byte *) SystemStack;
ASSERT(RAM_I_Zone_SIZE <= SYSTEM_STACK_SIZE);
return mb_mainzone;
}
if (i == 1)
{
/* Unused part of user stack (~200 kiB); provided by linker script */
extern byte sextra, eextra;
*size = &eextra - &sextra;
return &sextra;
}
return NULL;
}
//

View File

@ -33,11 +33,13 @@
// A check to determine which control system to compile for
//#define EMULATOR_CONTROLS 1
/* CGDOOM: I_ZoneBase() is extended with a second argument to support multiple
allocation zones, for more memory */
// Called by startup code
// to get the ammount of memory to malloc
// for the zone management.
byte* I_ZoneBase (int *size);
byte* I_ZoneBase (int *size, int zone_no);
// Called by D_DoomLoop,

View File

@ -110,7 +110,16 @@ static int W_AddFile ()
numlumps += header.numlumps;
// Fill in lumpinfo
lumpinfo = (lumpinfo_t *)CGDRealloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
// TODO: Actual realloc
if (!lumpinfo)
{
lumpinfo = (lumpinfo_t *)Z_Malloc (numlumps*sizeof(lumpinfo_t), PU_STATIC, 0);
}
else
{
I_Error ("realloc lumpinfo!");
lumpinfo = (lumpinfo_t *)CGDRealloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
}
if (!lumpinfo)
I_ErrorI ("CGDrealloc lumpinfo", (int)lumpinfo, numlumps, numlumps*sizeof(lumpinfo_t), 0);
@ -330,9 +339,7 @@ static void* W_CacheLumpNumCommon( int lump, int tag,int iEnableFlash)
/*if (lump==1203)
printf("sky access, returning %x \n",lumpcache[lump]);*/
int p1 = ((unsigned int)lumpcache[lump] & 0xf0000000) == 0x80000000;
int p2 = ((unsigned int)lumpcache[lump] & 0xf0000000) == 0xa0000000;
if(lumpcache[lump] == NULL || (!p1 && !p2))
if(lumpcache[lump] == NULL)
I_ErrorI("W_CacheLumpNumCommon", (int)lumpcache[lump], lump, 0, 0);
return lumpcache[lump];

View File

@ -51,9 +51,21 @@ typedef struct
memblock_t* rover;
} memzone_t;
/* CGDOOM: In order to increase available memory, we need to support multiple
zones. The code below is adapted to do that:
static memzone_t* mainzone;
* Z_ClearZone is already parameterized, nothing to do (it's never called)
* Z_Init is mostly replaced by a new function Z_AddZone()
* Z_Free is changed to detect which zone contains the pointer
* Z_Malloc is changed to try all zones
* Z_FreeTags is changed to iterate on all zones
* Z_CheckHeap is changed to iterate on all zones
* Z_ChangeTag2 operates on a single block and needs no change
* Z_FreeMemory is changed to iterate on all zones */
static memzone_t *zones[ZONE_MAX];
static int zone_count;
// static memzone_t* mainzone;
//
@ -81,27 +93,36 @@ void Z_ClearZone (memzone_t* zone)
//
// Z_Init
//
void Z_Init (void)
void Z_Init(void)
{
/* All work is left to Z_AddZone() */
zone_count = 0;
}
void Z_AddZone (void *buf, int size)
{
memblock_t* block;
int size;
mainzone = (memzone_t *)I_ZoneBase (&size);
mainzone->size = size;
if (zone_count >= ZONE_MAX)
return;
memzone_t* zone = (memzone_t *)buf;
zones[zone_count++] = zone;
zone->size = size;
// set the entire zone to one free block
mainzone->blocklist.next = mainzone->blocklist.prev = block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
zone->blocklist.next = zone->blocklist.prev = block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
mainzone->blocklist.user = (void **)mainzone;
mainzone->blocklist.tag = PU_STATIC;
mainzone->rover = block;
zone->blocklist.user = (void **)zone;
zone->blocklist.tag = PU_STATIC;
zone->rover = block;
block->prev = block->next = &mainzone->blocklist;
block->prev = block->next = &zone->blocklist;
// NULL indicates a free block.
block->user = NULL;
block->size = mainzone->size - sizeof(memzone_t);
block->size = zone->size - sizeof(memzone_t);
}
@ -113,10 +134,24 @@ void Z_Free (const void* ptr)
memblock_t* block;
memblock_t* other;
if(PTR_TO_FLASH(ptr))
if (PTR_TO_FLASH(ptr))
return;
memzone_t* zone = NULL;
for (int i = 0; i < zone_count; i++)
{
if (ptr >= (void *)zones[i] && ptr < (void *)zones[i] + zones[i]->size)
{
zone = zones[i];
break;
}
}
if (zone == NULL)
{
I_ErrorI ("Z_Free: Out of zone", (int)ptr, 0, 0, 0);
return;
}
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->id != ZONEID)
@ -147,9 +182,9 @@ void Z_Free (const void* ptr)
other->next = block->next;
other->next->prev = other;
if (block == mainzone->rover)
if (block == zone->rover)
{
mainzone->rover = other;
zone->rover = other;
}
block = other;
@ -163,9 +198,9 @@ void Z_Free (const void* ptr)
block->next = other->next;
block->next->prev = block;
if (other == mainzone->rover)
if (other == zone->rover)
{
mainzone->rover = block;
zone->rover = block;
}
}
}
@ -202,13 +237,6 @@ void* Z_Malloc( int size, int tag, void* user )
}
#endif
/*if(size > 64000)
{
char buf[21];
CGDAppendNum0_999("ENERR:",iCalled,1,buf);
I_Error(buf);
return 0;
}*/
// scan through the block list,
// looking for the first free block
// of sufficient size,
@ -217,49 +245,71 @@ void* Z_Malloc( int size, int tag, void* user )
// account for size of block header
size += sizeof(memblock_t);
// if there is a free block behind the rover,
// back up over them
base = mainzone->rover;
int zone_no = 0;
memzone_t *zone = zones[zone_no];
if (!base->prev->user)
for (;;)
{
base = base->prev;
}
// if there is a free block behind the rover,
// back up over them
base = zone->rover;
rover = base;
start = base->prev;
do
{
if (rover == start)
if (!base->prev->user)
{
// scanned all the way around the list
I_ErrorI ("Z_Malloc failure", size, 0, 0, 0);
base = base->prev;
}
if (rover->user)
rover = base;
start = base->prev;
int failed = 0;
do
{
if (rover->tag < PU_PURGELEVEL)
if (rover == start)
{
// hit a block that can't be purged,
// so move base past it
base = rover = rover->next;
// scanned all the way around the list
failed = 1;
break;
}
if (rover->user)
{
if (rover->tag < PU_PURGELEVEL)
{
// hit a block that can't be purged,
// so move base past it
base = rover = rover->next;
}
else
{
// free the rover block (adding the size to base)
// the rover can be the base block
base = base->prev;
Z_Free ((byte *)rover+sizeof(memblock_t));
base = base->next;
rover = base->next;
}
}
else
rover = rover->next;
} while (base->user || base->size < size);
if (failed)
{
if (zone_no + 1 < zone_count)
{
zone = zones[++zone_no];
continue;
}
else
{
// free the rover block (adding the size to base)
// the rover can be the base block
base = base->prev;
Z_Free ((byte *)rover+sizeof(memblock_t));
base = base->next;
rover = base->next;
I_ErrorI ("Z_Malloc failure", size, 0, 0, 0);
return NULL;
}
}
else
rover = rover->next;
} while (base->user || base->size < size);
else break;
}
// found a block big enough
extra = base->size - size;
@ -300,7 +350,7 @@ void* Z_Malloc( int size, int tag, void* user )
base->tag = tag;
// next allocation will start looking here
mainzone->rover = base->next;
zone->rover = base->next;
base->id = ZONEID;
@ -317,20 +367,25 @@ void Z_FreeTags(int lowtag,int hightag )
memblock_t* block;
memblock_t* next;
for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = next)
for (int i = 0; i < zone_count; i++)
{
// get link before freeing
next = block->next;
memzone_t* mainzone = zones[i];
// free block?
if (!block->user)
for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = next)
{
continue;
}
// get link before freeing
next = block->next;
if (block->tag >= lowtag && block->tag <= hightag)
{
Z_Free ( (byte *)block+sizeof(memblock_t));
// free block?
if (!block->user)
{
continue;
}
if (block->tag >= lowtag && block->tag <= hightag)
{
Z_Free ( (byte *)block+sizeof(memblock_t));
}
}
}
}
@ -342,27 +397,32 @@ void Z_CheckHeap (void)
{
memblock_t* block;
for (block = mainzone->blocklist.next ; ; block = block->next)
for (int i = 0; i < zone_count; i++)
{
if (block->next == &mainzone->blocklist)
{
// all blocks have been hit
break;
}
memzone_t* mainzone = zones[i];
if((byte *)block + block->size != (byte *)block->next)
for (block = mainzone->blocklist.next ; ; block = block->next)
{
I_Error("Z_CheckHeap: block size does not touch the next block\n");
}
if (block->next == &mainzone->blocklist)
{
// all blocks have been hit
break;
}
if(block->next->prev != block)
{
I_Error("Z_CheckHeap: next block doesn't have proper back link\n");
}
if((byte *)block + block->size != (byte *)block->next)
{
I_Error("Z_CheckHeap: block size does not touch the next block\n");
}
if(!block->user && !block->next->user)
{
I_Error("Z_CheckHeap: two consecutive free blocks\n");
if(block->next->prev != block)
{
I_Error("Z_CheckHeap: next block doesn't have proper back link\n");
}
if(!block->user && !block->next->user)
{
I_Error("Z_CheckHeap: two consecutive free blocks\n");
}
}
}
}
@ -406,11 +466,16 @@ int Z_FreeMemory (void)
memblock_t* block;
int free = 0;
for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = block->next)
for (int i = 0; i < zone_count; i++)
{
if (!block->user || block->tag >= PU_PURGELEVEL)
memzone_t* mainzone = zones[i];
for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = block->next)
{
free += block->size;
if (!block->user || block->tag >= PU_PURGELEVEL)
{
free += block->size;
}
}
}
return free;

View File

@ -54,6 +54,13 @@ void Z_CheckHeap (void);
void Z_ChangeTag2 (const void *ptr, int tag);
int Z_FreeMemory (void);
/* CGDOOM: Support for multiple zones is added; Z_Init() now does nothing,
zones need to be added manually (see D_DoomMain()). */
void Z_AddZone (void *zone, int size);
/* Maximum number of zones. */
#define ZONE_MAX 16
typedef struct memblock_s
{