📄 enhanced_zone_handling.txt
字号:
================================================================
Title : Tutorial: Implementing the Enhanced Zone Handling into the Quake engine
Date : 2001-09-20
Filename : ENHANCED_ZONE_HANDLING.TXT
Author : Matthias "Maddes" Buecher
Email Address : maddes@go.to
Homepage : Quake Info Pool
http://www.quake-info-pool.net/
Quake Standards Group (short QSG)
http://www.quakesrc.org/
Complexity : Moderate
================================================================
On some occassions you can see that id wanted to use different zones, but the
implementation in the original source only deals with "mainzone".
This tutorial will enhance the zone handling of the Quake engine to handle many
different zones. To accomplish this all zone handling functions will get a zone
pointer as a new parameter, which tells them the zone to process.
But first we will increase the default/minimum size for the mainzone.
At top of ZONE.C remove the definition of DYNAMIC_SIZE and place the new
definition ZONE_MIN_SIZE at top of ZONE.H. This way you can access it in the
whole source code.
#define ZONE_MIN_SIZE 128*1024 // 128K // 2001-09-20 Increased default zone by Maddes
In ZONE.C change all occurences of DYNAMIC_SIZE into ZONE_MIN_SIZE.
At the end of ZONE.C in Memory_Init() change...
p = COM_CheckParm ("-zone");
if (p)
{
if (p < com_argc-1)
zonesize = Q_atoi (com_argv[p+1]) * 1024;
else
Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
}
... into ...
p = COM_CheckParm ("-zone");
if (p)
{
if (p < com_argc-1)
{ // 2001-09-20 Increased default zone by Maddes
zonesize = Q_atoi (com_argv[p+1]) * 1024;
// 2001-09-20 Increased default zone by Maddes start
if (zonesize < ZONE_MIN_SIZE)
{
zonesize = ZONE_MIN_SIZE;
}
}
// 2001-09-20 Increased default zone by Maddes end
else
Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
}
Now we will add the new parameter "memzone_t *zone" to all Z_* functions in ZONE.C.
Just add it as the first parameter like it already is for Z_ClearZone() and
Z_Print(), for example the definition of Z_Free() will look like this...
void Z_Free (memzone_t *zone, void *ptr) // 2001-09-20 Enhanced zone handling by Maddes
Also change Z_Malloc(), Z_TagMalloc() and Z_CheckHeap() accordingly.
To make the functions work as we want to, you have to replace the usage of
"mainzone" with the "zone" parameter in all Z_* functions of ZONE.C. This is
necessary in Z_Free(), Z_Malloc(), Z_TagMalloc(), Z_Print() and Z_CheckHeap().
Note that Z_Malloc() also calls Z_CheckHeap() and Z_TagMalloc(), and you have to
pass the "zone" parameter too.
As the functions have changed, we have to change their declarations in ZONE.H.
The structure definitions of "memblock_t" and "memzone_t" have to be moved from
ZONE.C to ZONE.H too, as "mainzone" has to be declared in ZONE.H, so we can use
it throughout the engine for the Z_Malloc() and Z_Free() calls.
Add the definitions at the top of ZONE.H ...
// 2001-09-20 Enhanced zone handling by Maddes start
typedef struct memblock_s
{
int size; // including the header and possibly tiny fragments
int tag; // a tag of 0 is a free block
int id; // should be ZONEID
struct memblock_s *next, *prev;
// int pad; // pad to 64-bit / 8-byte boundary
struct memzone_s *zone;
} memblock_t;
typedef struct memzone_s
{
int size; // total bytes malloced, including header
memblock_t blocklist; // start / end cap for linked list
memblock_t *rover;
} memzone_t;
extern memzone_t *mainzone;
// 2001-09-20 Enhanced zone handling by Maddes end
... and delete those lines from the top of ZONE.C.
Change the function declarations in ZONE.H from ...
void Z_Free (void *ptr);
void *Z_Malloc (int size); // returns 0 filled memory
void *Z_TagMalloc (int size, int tag);
void Z_DumpHeap (void);
void Z_CheckHeap (void);
int Z_FreeMemory (void);
... into ...
// 2001-09-20 Enhanced zone handling by Maddes start
void Z_ClearZone (memzone_t *zone, int size);
void Z_Free (memzone_t *zone, void *ptr);
void *Z_Malloc (memzone_t *zone, int size); // returns 0 filled memory
void *Z_TagMalloc (memzone_t *zone, int size, int tag);
void Z_Print (memzone_t *zone);
void Z_CheckHeap (memzone_t *zone);
// 2001-09-20 Enhanced zone handling by Maddes end
... which also removes the declarations of unexisting functions.
To make the engine compile again, add "mainzone" as the first parameter to all
calls of Z_Free() and Z_Malloc() throughout the engine.
The engine can now handle different zones, but if something goes wrong while
allocating or freeing memory then we don't know in which zone the error occured.
Move the structure definition of "hunk_t" to the top of ZONE.C and change Z_Free() to...
void Z_Free (memzone_t *zone, void *ptr) // 2001-09-20 Enhanced zone handling by Maddes
{
memblock_t *block, *other;
// 2001-09-20 Enhanced zone handling by Maddes start
hunk_t *h;
h = (hunk_t *)zone;
h--;
// 2001-09-20 Enhanced zone handling by Maddes end
if (!ptr)
Sys_Error ("Z_Free: NULL pointer");
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->id != ZONEID)
// 2001-09-20 Enhanced zone handling by Maddes start
{
// Sys_Error ("Z_Free: freed a pointer without ZONEID");
Sys_Error ("Z_Free: freed a pointer without ZONEID in \"%s\"", h->name);
}
// 2001-09-20 Enhanced zone handling by Maddes end
if (block->tag == 0)
// 2001-09-20 Enhanced zone handling by Maddes start
{
// Sys_Error ("Z_Free: freed a freed pointer");
Sys_Error ("Z_Free: freed a freed pointer in \"%s\"", h->name);
}
// 2001-09-20 Enhanced zone handling by Maddes end
// 2001-09-20 Enhanced zone handling by Maddes start
if (block->zone != zone)
{
Sys_Error ("Z_Free: freed a foreign pointer in \"%s\"\n", h->name);
}
// 2001-09-20 Enhanced zone handling by Maddes end
block->tag = 0; // mark as free
other = block->prev;
if (!other->tag)
{ // merge with previous free block
other->size += block->size;
other->next = block->next;
other->next->prev = other;
if (block == zone->rover) // 2001-09-20 Enhanced zone handling by Maddes
zone->rover = other; // 2001-09-20 Enhanced zone handling by Maddes
block = other;
}
other = block->next;
if (!other->tag)
{ // merge the next free block onto the end
block->size += other->size;
block->next = other->next;
block->next->prev = block;
if (other == zone->rover) // 2001-09-20 Enhanced zone handling by Maddes
zone->rover = block; // 2001-09-20 Enhanced zone handling by Maddes
}
}
... and do a similar change to Z_Malloc() ...
void *Z_Malloc (memzone_t *zone, int size) // 2001-09-20 Enhanced zone handling by Maddes
{
void *buf;
Z_CheckHeap (zone); // DEBUG // 2001-09-20 Enhanced zone handling by Maddes
buf = Z_TagMalloc (zone, size, 1); // 2001-09-20 Enhanced zone handling by Maddes
if (!buf)
// 2001-09-20 Enhanced zone handling by Maddes start
{
hunk_t *h;
h = (hunk_t *)zone;
h--;
// Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
Sys_Error ("Z_Malloc: failed on allocation of %i bytes in \"%s\"", size, h->name);
}
// 2001-09-20 Enhanced zone handling by Maddes end
Q_memset (buf, 0, size);
return buf;
}
... at last we have to set the original zone of the block in Z_TagMalloc after
the id of the block is set...
base->id = ZONEID;
base->zone = zone; // 2001-09-20 Enhanced zone handling by Maddes
Done.
When you add a new zone to the engine, define a zone pointer at top of ZONE.C...
// 2001-09-20 New tutorial zone by Maddes start
memzone_t *zone_sample;
int zonesize_sample;
// 2001-09-20 New tutorial zone by Maddes end
... declare it in ZONE.H for other source files ...
// 2001-09-20 New tutorial zone by Maddes start
extern memzone_t *zone_sample;
extern int zonesize_sample;
// 2001-09-20 New tutorial zone by Maddes end
... and allocate the zone memory at the end of Z_MemoryInit() in ZONE.C ...
// 2001-09-20 New tutorial zone by Maddes start
zonesize_sample = ZONE_MIN_SIZE;
p = COM_CheckParm ("-samplezone");
if (p)
{
if (p < com_argc-1)
{
zonesize_sample = Q_atoi (com_argv[p+1]) * 1024;
if (zonesize_sample < ZONE_MIN_SIZE)
{
zonesize_sample = ZONE_MIN_SIZE;
}
}
else
Sys_Error ("Memory_Init: you must specify a size in KB after -samplezone");
}
zone_sample = Hunk_AllocName (zonesize_sample, "sample");
Z_ClearZone (zone_sample, zonesize_sample);
// 2001-09-20 New tutorial zone by Maddes end
Note that the zone name should only have 7 characters.
Now you can use the new zone throughout the engine in the following way...
void *ptr;
Z_ClearZone (zone_sample, zonesize_sample);
...
ptr = Z_Malloc (zone_sample, 1024);
...
Z_Free (zone_sample, ptr);
That's it for the zone handling.
At last I show you how to add two new commands which help you to determine how
much mem is allocated for all the hunks and caches.
The first is "cachelist", just add the following line at the end of Memory_Init()...
Cmd_AddCommand ("cachelist", Cache_Print); // 2001-09-20 Cachelist command by Maddes
The second is "hunklist", add the following function behind Hunk_Print()...
// 2001-09-20 Hunklist command by Maddes start
/*
===================
Hunk_Print_f
===================
*/
void Hunk_Print_f(void)
{
qboolean showall;
showall = 0;
if (Cmd_Argc() > 1)
{
showall = Q_atoi(Cmd_Argv(1));
}
Hunk_Print(showall);
}
// 2001-09-20 Hunklist command by Maddes end
...and again add the following line at the end of Memory_Init()...
Cmd_AddCommand ("hunklist", Hunk_Print_f); // 2001-09-20 Hunklist command by Maddes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -