set the include directory
[AROS-Contrib.git] / Games / Doom / z_zone.c
bloba90b688a5e3a3737d4e6121fec47c375ae97631a
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
17 // $Log$
18 // Revision 1.1 2000/02/29 18:21:05 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
22 // DESCRIPTION:
23 // Zone Memory Allocation. Neat.
25 //-----------------------------------------------------------------------------
27 static const char
28 rcsid[] = "$Id$";
30 #include "z_zone.h"
31 #include "i_system.h"
32 #include "doomdef.h"
36 // ZONE MEMORY ALLOCATION
38 // There is never any space between memblocks,
39 // and there will never be two contiguous free memblocks.
40 // The rover can be left pointing at a non-empty block.
42 // It is of no value to free a cachable block,
43 // because it will get overwritten automatically if needed.
44 //
46 #define ZONEID 0x1d4a11
49 typedef struct
51 // total bytes malloced, including header
52 int size;
54 // start / end cap for linked list
55 memblock_t blocklist;
57 memblock_t* rover;
59 } memzone_t;
63 memzone_t* mainzone;
68 // Z_ClearZone
70 void Z_ClearZone (memzone_t* zone)
72 memblock_t* block;
74 // set the entire zone to one free block
75 zone->blocklist.next =
76 zone->blocklist.prev =
77 block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
79 zone->blocklist.user = (void *)zone;
80 zone->blocklist.tag = PU_STATIC;
81 zone->rover = block;
83 block->prev = block->next = &zone->blocklist;
85 // NULL indicates a free block.
86 block->user = NULL;
88 block->size = zone->size - sizeof(memzone_t);
94 // Z_Init
96 void Z_Init (void)
98 memblock_t* block;
99 int size;
101 mainzone = (memzone_t *)I_ZoneBase (&size);
102 mainzone->size = size;
104 // set the entire zone to one free block
105 mainzone->blocklist.next =
106 mainzone->blocklist.prev =
107 block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
109 mainzone->blocklist.user = (void *)mainzone;
110 mainzone->blocklist.tag = PU_STATIC;
111 mainzone->rover = block;
113 block->prev = block->next = &mainzone->blocklist;
115 // NULL indicates a free block.
116 block->user = NULL;
118 block->size = mainzone->size - sizeof(memzone_t);
123 // Z_Free
125 void Z_Free (void* ptr)
127 memblock_t* block;
128 memblock_t* other;
130 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
132 if (block->id != ZONEID)
133 I_Error ("Z_Free: freed a pointer without ZONEID");
135 if (block->user > (void **)0x100)
137 // smaller values are not pointers
138 // Note: OS-dependend?
140 // clear the user's mark
141 *block->user = 0;
144 // mark as free
145 block->user = NULL;
146 block->tag = 0;
147 block->id = 0;
149 other = block->prev;
151 if (!other->user)
153 // merge with previous free block
154 other->size += block->size;
155 other->next = block->next;
156 other->next->prev = other;
158 if (block == mainzone->rover)
159 mainzone->rover = other;
161 block = other;
164 other = block->next;
165 if (!other->user)
167 // merge the next free block onto the end
168 block->size += other->size;
169 block->next = other->next;
170 block->next->prev = block;
172 if (other == mainzone->rover)
173 mainzone->rover = block;
180 // Z_Malloc
181 // You can pass a NULL user if the tag is < PU_PURGELEVEL.
183 #define MINFRAGMENT 64
186 void*
187 Z_Malloc
188 ( int size,
189 int tag,
190 void* user )
192 int extra;
193 memblock_t* start;
194 memblock_t* rover;
195 memblock_t* newblock;
196 memblock_t* base;
198 size = (size + 31) & ~31;
200 // scan through the block list,
201 // looking for the first free block
202 // of sufficient size,
203 // throwing out any purgable blocks along the way.
205 // account for size of block header
206 size += sizeof(memblock_t);
208 // if there is a free block behind the rover,
209 // back up over them
210 base = mainzone->rover;
212 if (!base->prev->user)
213 base = base->prev;
215 rover = base;
216 start = base->prev;
220 if (rover == start)
222 // scanned all the way around the list
223 I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
226 if (rover->user)
228 if (rover->tag < PU_PURGELEVEL)
230 // hit a block that can't be purged,
231 // so move base past it
232 base = rover = rover->next;
234 else
236 // free the rover block (adding the size to base)
238 // the rover can be the base block
239 base = base->prev;
240 Z_Free ((byte *)rover+sizeof(memblock_t));
241 base = base->next;
242 rover = base->next;
245 else
246 rover = rover->next;
247 } while (base->user || base->size < size);
250 // found a block big enough
251 extra = base->size - size;
253 if (extra > MINFRAGMENT)
255 // there will be a free fragment after the allocated block
256 newblock = (memblock_t *) ((byte *)base + size );
257 newblock->size = extra;
259 // NULL indicates free block.
260 newblock->user = NULL;
261 newblock->tag = 0;
262 newblock->prev = base;
263 newblock->next = base->next;
264 newblock->next->prev = newblock;
266 base->next = newblock;
267 base->size = size;
270 if (user)
272 // mark as an in use block
273 base->user = user;
274 *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
276 else
278 if (tag >= PU_PURGELEVEL)
279 I_Error ("Z_Malloc: an owner is required for purgable blocks");
281 // mark as in use, but unowned
282 base->user = (void *)2;
284 base->tag = tag;
286 // next allocation will start looking here
287 mainzone->rover = base->next;
289 base->id = ZONEID;
291 return (void *) ((byte *)base + sizeof(memblock_t));
297 // Z_FreeTags
299 void
300 Z_FreeTags
301 ( int lowtag,
302 int hightag )
304 memblock_t* block;
305 memblock_t* next;
307 for (block = mainzone->blocklist.next ;
308 block != &mainzone->blocklist ;
309 block = next)
311 // get link before freeing
312 next = block->next;
314 // free block?
315 if (!block->user)
316 continue;
318 if (block->tag >= lowtag && block->tag <= hightag)
319 Z_Free ( (byte *)block+sizeof(memblock_t));
326 // Z_DumpHeap
327 // Note: TFileDumpHeap( stdout ) ?
329 void
330 Z_DumpHeap
331 ( int lowtag,
332 int hightag )
334 memblock_t* block;
336 printf ("zone size: %i location: %p\n",
337 mainzone->size,mainzone);
339 printf ("tag range: %i to %i\n",
340 lowtag, hightag);
342 for (block = mainzone->blocklist.next ; ; block = block->next)
344 if (block->tag >= lowtag && block->tag <= hightag)
345 printf ("block:%p size:%7i user:%p tag:%3i\n",
346 block, block->size, block->user, block->tag);
348 if (block->next == &mainzone->blocklist)
350 // all blocks have been hit
351 break;
354 if ( (byte *)block + block->size != (byte *)block->next)
355 printf ("ERROR: block size does not touch the next block\n");
357 if ( block->next->prev != block)
358 printf ("ERROR: next block doesn't have proper back link\n");
360 if (!block->user && !block->next->user)
361 printf ("ERROR: two consecutive free blocks\n");
367 // Z_FileDumpHeap
369 void Z_FileDumpHeap (FILE* f)
371 memblock_t* block;
373 fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone);
375 for (block = mainzone->blocklist.next ; ; block = block->next)
377 fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
378 block, block->size, block->user, block->tag);
380 if (block->next == &mainzone->blocklist)
382 // all blocks have been hit
383 break;
386 if ( (byte *)block + block->size != (byte *)block->next)
387 fprintf (f,"ERROR: block size does not touch the next block\n");
389 if ( block->next->prev != block)
390 fprintf (f,"ERROR: next block doesn't have proper back link\n");
392 if (!block->user && !block->next->user)
393 fprintf (f,"ERROR: two consecutive free blocks\n");
400 // Z_CheckHeap
402 void Z_CheckHeap (void)
404 memblock_t* block;
406 for (block = mainzone->blocklist.next ; ; block = block->next)
408 if (block->next == &mainzone->blocklist)
410 // all blocks have been hit
411 break;
414 if ( (byte *)block + block->size != (byte *)block->next)
415 I_Error ("Z_CheckHeap: block size does not touch the next block\n");
417 if ( block->next->prev != block)
418 I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
420 if (!block->user && !block->next->user)
421 I_Error ("Z_CheckHeap: two consecutive free blocks\n");
429 // Z_ChangeTag
431 void
432 Z_ChangeTag2
433 ( void* ptr,
434 int tag )
436 memblock_t* block;
438 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
440 if (block->id != ZONEID)
441 I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
443 if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
444 I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
446 block->tag = tag;
452 // Z_FreeMemory
454 int Z_FreeMemory (void)
456 memblock_t* block;
457 int free;
459 free = 0;
461 for (block = mainzone->blocklist.next ;
462 block != &mainzone->blocklist;
463 block = block->next)
465 if (!block->user || block->tag >= PU_PURGELEVEL)
466 free += block->size;
468 return free;