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 |