Tutorial *118*

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



 
Not logged in
Sign up
Login:
Passwd: