1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
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
18 // Revision 1.1 2000/02/29 18:21:05 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // Zone Memory Allocation. Neat.
25 //-----------------------------------------------------------------------------
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.
46 #define ZONEID 0x1d4a11
51 // total bytes malloced, including header
54 // start / end cap for linked list
70 void Z_ClearZone (memzone_t
* zone
)
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
;
83 block
->prev
= block
->next
= &zone
->blocklist
;
85 // NULL indicates a free block.
88 block
->size
= zone
->size
- sizeof(memzone_t
);
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.
118 block
->size
= mainzone
->size
- sizeof(memzone_t
);
125 void Z_Free (void* ptr
)
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
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
;
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
;
181 // You can pass a NULL user if the tag is < PU_PURGELEVEL.
183 #define MINFRAGMENT 64
195 memblock_t
* newblock
;
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,
210 base
= mainzone
->rover
;
212 if (!base
->prev
->user
)
222 // scanned all the way around the list
223 I_Error ("Z_Malloc: failed on allocation of %i bytes", size
);
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
;
236 // free the rover block (adding the size to base)
238 // the rover can be the base block
240 Z_Free ((byte
*)rover
+sizeof(memblock_t
));
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
;
262 newblock
->prev
= base
;
263 newblock
->next
= base
->next
;
264 newblock
->next
->prev
= newblock
;
266 base
->next
= newblock
;
272 // mark as an in use block
274 *(void **)user
= (void *) ((byte
*)base
+ sizeof(memblock_t
));
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;
286 // next allocation will start looking here
287 mainzone
->rover
= base
->next
;
291 return (void *) ((byte
*)base
+ sizeof(memblock_t
));
307 for (block
= mainzone
->blocklist
.next
;
308 block
!= &mainzone
->blocklist
;
311 // get link before freeing
318 if (block
->tag
>= lowtag
&& block
->tag
<= hightag
)
319 Z_Free ( (byte
*)block
+sizeof(memblock_t
));
327 // Note: TFileDumpHeap( stdout ) ?
336 printf ("zone size: %i location: %p\n",
337 mainzone
->size
,mainzone
);
339 printf ("tag range: %i to %i\n",
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
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");
369 void Z_FileDumpHeap (FILE* f
)
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
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");
402 void Z_CheckHeap (void)
406 for (block
= mainzone
->blocklist
.next
; ; block
= block
->next
)
408 if (block
->next
== &mainzone
->blocklist
)
410 // all blocks have been hit
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");
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");
454 int Z_FreeMemory (void)
461 for (block
= mainzone
->blocklist
.next
;
462 block
!= &mainzone
->blocklist
;
465 if (!block
->user
|| block
->tag
>= PU_PURGELEVEL
)