diff options
Diffstat (limited to 'apps/plugins/doom/z_zone.c')
-rw-r--r-- | apps/plugins/doom/z_zone.c | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/apps/plugins/doom/z_zone.c b/apps/plugins/doom/z_zone.c new file mode 100644 index 0000000000..036c995743 --- /dev/null +++ b/apps/plugins/doom/z_zone.c | |||
@@ -0,0 +1,666 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
5 | * PrBoom a Doom port merged with LxDoom and LSDLDoom | ||
6 | * based on BOOM, a modified and improved DOOM engine | ||
7 | * Copyright (C) 1999 by | ||
8 | * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman | ||
9 | * Copyright (C) 1999-2000 by | ||
10 | * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
25 | * 02111-1307, USA. | ||
26 | * | ||
27 | * DESCRIPTION: | ||
28 | * Zone Memory Allocation. Neat. | ||
29 | * | ||
30 | * Neat enough to be rewritten by Lee Killough... | ||
31 | * | ||
32 | * Must not have been real neat :) | ||
33 | * | ||
34 | * Made faster and more general, and added wrappers for all of Doom's | ||
35 | * memory allocation functions, including malloc() and similar functions. | ||
36 | * Added line and file numbers, in case of error. Added performance | ||
37 | * statistics and tunables. | ||
38 | *----------------------------------------------------------------------------- | ||
39 | */ | ||
40 | |||
41 | #include "z_zone.h" | ||
42 | #include "z_bmalloc.h" | ||
43 | #include "doomdef.h" | ||
44 | #include "i_system.h" | ||
45 | #include "rockmacros.h" | ||
46 | #include "m_argv.h" | ||
47 | |||
48 | // Tunables | ||
49 | |||
50 | // Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE) | ||
51 | #define CACHE_ALIGN 32 | ||
52 | |||
53 | // Minimum chunk size at which blocks are allocated | ||
54 | #define CHUNK_SIZE 32 | ||
55 | |||
56 | // Minimum size a block must be to become part of a split | ||
57 | #define MIN_BLOCK_SPLIT (1024) | ||
58 | |||
59 | // Minimum RAM machine is assumed to have | ||
60 | /* cph - Select zone size. 6megs is usable, but with the SDL version | ||
61 | * storing sounds in the zone, 8 is more sensible */ | ||
62 | #define MIN_RAM (8*1024*1024) | ||
63 | |||
64 | // Amount to subtract when retrying failed attempts to allocate initial pool | ||
65 | #define RETRY_AMOUNT (256*1024) | ||
66 | |||
67 | // signature for block header | ||
68 | #define ZONEID 0x931d4a11 | ||
69 | |||
70 | // Number of mallocs & frees kept in history buffer (must be a power of 2) | ||
71 | #define ZONE_HISTORY 4 | ||
72 | |||
73 | // End Tunables | ||
74 | |||
75 | typedef struct memblock { | ||
76 | |||
77 | #ifdef ZONEIDCHECK | ||
78 | unsigned id; | ||
79 | #endif | ||
80 | |||
81 | struct memblock *next,*prev; | ||
82 | size_t size; | ||
83 | void **user; | ||
84 | unsigned char tag,vm; | ||
85 | |||
86 | #ifdef INSTRUMENTED | ||
87 | unsigned short extra; | ||
88 | const char *file; | ||
89 | int line; | ||
90 | #endif | ||
91 | |||
92 | } memblock_t; | ||
93 | |||
94 | /* size of block header | ||
95 | * cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on | ||
96 | * 64bit architectures */ | ||
97 | static const size_t HEADER_SIZE IDATA_ATTR= (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); | ||
98 | |||
99 | static memblock_t *rover IBSS_ATTR; // roving pointer to memory blocks | ||
100 | static memblock_t *zone IBSS_ATTR; // pointer to first block | ||
101 | static memblock_t *zonebase IBSS_ATTR; // pointer to entire zone memory | ||
102 | static size_t zonebase_size IBSS_ATTR; // zone memory allocated size | ||
103 | |||
104 | #ifdef INSTRUMENTED | ||
105 | |||
106 | // statistics for evaluating performance | ||
107 | static size_t free_memory; | ||
108 | static size_t active_memory; | ||
109 | static size_t purgable_memory; | ||
110 | static size_t inactive_memory; | ||
111 | static size_t virtual_memory; | ||
112 | |||
113 | static void Z_PrintStats(void) // Print allocation statistics | ||
114 | { | ||
115 | unsigned long total_memory = free_memory + active_memory + | ||
116 | purgable_memory + inactive_memory + | ||
117 | virtual_memory; | ||
118 | double s = 100.0 / total_memory; | ||
119 | |||
120 | doom_printf("%-5u\t%6.01f%%\tstatic\n" | ||
121 | "%-5u\t%6.01f%%\tpurgable\n" | ||
122 | "%-5u\t%6.01f%%\tfree\n" | ||
123 | "%-5u\t%6.01f%%\tfragmentary\n" | ||
124 | "%-5u\t%6.01f%%\tvirtual\n" | ||
125 | "%-5lu\t\ttotal\n", | ||
126 | active_memory, | ||
127 | active_memory*s, | ||
128 | purgable_memory, | ||
129 | purgable_memory*s, | ||
130 | free_memory, | ||
131 | free_memory*s, | ||
132 | inactive_memory, | ||
133 | inactive_memory*s, | ||
134 | virtual_memory, | ||
135 | virtual_memory*s, | ||
136 | total_memory | ||
137 | ); | ||
138 | } | ||
139 | |||
140 | #ifdef HEAPDUMP | ||
141 | void W_PrintLump(FILE* fp, void* p); | ||
142 | |||
143 | void Z_DumpMemory(void) | ||
144 | { | ||
145 | static int dump; | ||
146 | memblock_t* block = zone; | ||
147 | char buf[80]; | ||
148 | FILE* fp; | ||
149 | size_t total_cache = 0, total_free = 0, total_malloc = 0; | ||
150 | |||
151 | sprintf(buf, "memdump.%d", dump++); | ||
152 | fp = fopen(buf, "w"); | ||
153 | do { | ||
154 | switch (block->tag) { | ||
155 | case PU_FREE: | ||
156 | fprintf(fp, "free %d\n", block->size); | ||
157 | total_free += block->size; | ||
158 | break; | ||
159 | case PU_CACHE: | ||
160 | fprintf(fp, "cache %s:%d:%d\n", block->file, block->line, block->size); | ||
161 | total_cache += block->size; | ||
162 | break; | ||
163 | case PU_LEVEL: | ||
164 | fprintf(fp, "level %s:%d:%d\n", block->file, block->line, block->size); | ||
165 | total_malloc += block->size; | ||
166 | break; | ||
167 | default: | ||
168 | fprintf(fp, "malloc %s:%d:%d", block->file, block->line, block->size); | ||
169 | total_malloc += block->size; | ||
170 | if (!strcmp(block->file,"w_wad.c")) W_PrintLump(fp, (char*)block + HEADER_SIZE); | ||
171 | fputc('\n', fp); | ||
172 | break; | ||
173 | } | ||
174 | block=block->next; | ||
175 | } while (block != zone); | ||
176 | fprintf(fp, "malloc %d, cache %d, free %d, total %d\n", | ||
177 | total_malloc, total_cache, total_free, | ||
178 | total_malloc + total_cache + total_free); | ||
179 | fclose(fp); | ||
180 | } | ||
181 | #endif | ||
182 | #endif | ||
183 | |||
184 | #ifdef INSTRUMENTED | ||
185 | |||
186 | // killough 4/26/98: Add history information | ||
187 | |||
188 | enum {malloc_history, free_history, NUM_HISTORY_TYPES}; | ||
189 | |||
190 | static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; | ||
191 | static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; | ||
192 | static int history_index[NUM_HISTORY_TYPES]; | ||
193 | static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"}; | ||
194 | |||
195 | void Z_DumpHistory(char *buf) | ||
196 | { | ||
197 | int i,j; | ||
198 | char s[1024]; | ||
199 | strcat(buf,"\n"); | ||
200 | for (i=0;i<NUM_HISTORY_TYPES;i++) | ||
201 | { | ||
202 | sprintf(s,"\nLast several %s:\n\n", desc[i]); | ||
203 | strcat(buf,s); | ||
204 | for (j=0; j<ZONE_HISTORY; j++) | ||
205 | { | ||
206 | int k = (history_index[i]-j-1) & (ZONE_HISTORY-1); | ||
207 | if (file_history[i][k]) | ||
208 | { | ||
209 | sprintf(s, "File: %s, Line: %d\n", file_history[i][k], | ||
210 | line_history[i][k]); | ||
211 | strcat(buf,s); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | #else | ||
217 | |||
218 | void Z_DumpHistory(char *buf) | ||
219 | { | ||
220 | (void)buf; | ||
221 | } | ||
222 | |||
223 | #endif | ||
224 | |||
225 | void Z_Close(void) | ||
226 | { | ||
227 | // (free)(zonebase); | ||
228 | zone = rover = zonebase = NULL; | ||
229 | } | ||
230 | |||
231 | void Z_Init(void) | ||
232 | { | ||
233 | unsigned int size; | ||
234 | #ifdef INSTRUMENTED | ||
235 | if (!(HEADER_SIZE >= sizeof(memblock_t) && MIN_RAM > LEAVE_ASIDE)) | ||
236 | I_Error("Z_Init: Sanity check failed"); | ||
237 | #endif | ||
238 | |||
239 | // atexit(Z_Close); // exit handler | ||
240 | |||
241 | // Allocate the memory | ||
242 | |||
243 | zonebase=rb->plugin_get_audio_buffer(&size); | ||
244 | size-=2*(HEADER_SIZE + CACHE_ALIGN); // Leave space for header and CACHE_ALIGN | ||
245 | size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size | ||
246 | size += HEADER_SIZE + CACHE_ALIGN; | ||
247 | |||
248 | zonebase_size=size; | ||
249 | |||
250 | printf("Z_Init: Allocated %dKb zone memory\n", (long unsigned)size >> 10); | ||
251 | |||
252 | // Align on cache boundary | ||
253 | |||
254 | zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN - | ||
255 | ((unsigned) zonebase & (CACHE_ALIGN-1))); | ||
256 | |||
257 | rover = zone; // Rover points to base of zone mem | ||
258 | zone->next = zone->prev = zone; // Single node | ||
259 | zone->size = size; // All memory in one block | ||
260 | zone->tag = PU_FREE; // A free block | ||
261 | zone->vm = 0; | ||
262 | |||
263 | #ifdef ZONEIDCHECK | ||
264 | zone->id = 0; | ||
265 | #endif | ||
266 | |||
267 | #ifdef INSTRUMENTED | ||
268 | free_memory = size; | ||
269 | inactive_memory = zonebase_size - size; | ||
270 | active_memory = purgable_memory = virtual_memory = 0; | ||
271 | #endif | ||
272 | } | ||
273 | |||
274 | /* Z_Malloc | ||
275 | * You can pass a NULL user if the tag is < PU_PURGELEVEL. | ||
276 | * | ||
277 | * cph - the algorithm here was a very simple first-fit round-robin | ||
278 | * one - just keep looping around, freeing everything we can until | ||
279 | * we get a large enough space | ||
280 | * | ||
281 | * This has been changed now; we still do the round-robin first-fit, | ||
282 | * but we only free the blocks we actually end up using; we don't | ||
283 | * free all the stuff we just pass on the way. | ||
284 | */ | ||
285 | |||
286 | void *(Z_Malloc)(size_t size, int tag, void **user | ||
287 | #ifdef INSTRUMENTED | ||
288 | , const char *file, int line | ||
289 | #endif | ||
290 | ) | ||
291 | { | ||
292 | register memblock_t *block; | ||
293 | memblock_t *start, *first_of_free; | ||
294 | register size_t contig_free; | ||
295 | |||
296 | #ifdef INSTRUMENTED | ||
297 | size_t size_orig = size; | ||
298 | #ifdef CHECKHEAP | ||
299 | Z_CheckHeap(); | ||
300 | #endif | ||
301 | |||
302 | file_history[malloc_history][history_index[malloc_history]] = file; | ||
303 | line_history[malloc_history][history_index[malloc_history]++] = line; | ||
304 | history_index[malloc_history] &= ZONE_HISTORY-1; | ||
305 | #endif | ||
306 | |||
307 | #ifdef ZONEIDCHECK | ||
308 | if (tag >= PU_PURGELEVEL && !user) | ||
309 | I_Error ("Z_Malloc: An owner is required for purgable blocks" | ||
310 | #ifdef INSTRUMENTED | ||
311 | "Source: %s:%d", file, line | ||
312 | #endif | ||
313 | ); | ||
314 | #endif | ||
315 | |||
316 | if (!size) | ||
317 | return user ? *user = NULL : NULL; // malloc(0) returns NULL | ||
318 | |||
319 | size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size | ||
320 | |||
321 | block = rover; | ||
322 | |||
323 | if (block->prev->tag == PU_FREE) | ||
324 | block = block->prev; | ||
325 | |||
326 | start = block; | ||
327 | first_of_free = NULL; contig_free = 0; | ||
328 | |||
329 | do { | ||
330 | /* If we just wrapped, we're not contiguous with the previous block */ | ||
331 | if (block == zone) contig_free = 0; | ||
332 | |||
333 | if (block->tag < PU_PURGELEVEL && block->tag != PU_FREE) { | ||
334 | /* Not free(able), so no free space here */ | ||
335 | contig_free = 0; | ||
336 | } else { | ||
337 | /* Add to contiguous chunk of free space */ | ||
338 | if (!contig_free) first_of_free = block; | ||
339 | contig_free += block->size; | ||
340 | |||
341 | /* First fit */ | ||
342 | if (contig_free >= size) | ||
343 | break; | ||
344 | } | ||
345 | } | ||
346 | while ((block = block->next) != start); // detect cycles as failure | ||
347 | |||
348 | if (contig_free >= size) { | ||
349 | /* We have a block of free(able) memory on the heap which will suffice */ | ||
350 | block = first_of_free; | ||
351 | |||
352 | /* If the previous block is adjacent and free, step back and include it */ | ||
353 | if (block != zone && block->prev->tag == PU_FREE) | ||
354 | block = block->prev; | ||
355 | |||
356 | /* Free current block if needed */ | ||
357 | if (block->tag != PU_FREE) Z_Free((char *) block + HEADER_SIZE); | ||
358 | |||
359 | /* Note: guaranteed that block->prev is either | ||
360 | * not free or not contiguous | ||
361 | * | ||
362 | * At every step, block->next must be not free, else it would | ||
363 | * have been merged with our block | ||
364 | * No range check needed because we know it works by the previous loop */ | ||
365 | while (block->size < size) | ||
366 | Z_Free((char *)(block->next) + HEADER_SIZE); | ||
367 | |||
368 | /* Now, carve up the block */ | ||
369 | { | ||
370 | size_t extra = block->size - size; | ||
371 | if (extra >= MIN_BLOCK_SPLIT + HEADER_SIZE) { | ||
372 | memblock_t *newb = (memblock_t *)((char *) block + | ||
373 | HEADER_SIZE + size); | ||
374 | |||
375 | (newb->next = block->next)->prev = newb; | ||
376 | (newb->prev = block)->next = newb; // Split up block | ||
377 | block->size = size; | ||
378 | newb->size = extra - HEADER_SIZE; | ||
379 | newb->tag = PU_FREE; | ||
380 | newb->vm = 0; | ||
381 | |||
382 | #ifdef INSTRUMENTED | ||
383 | inactive_memory += HEADER_SIZE; | ||
384 | free_memory -= HEADER_SIZE; | ||
385 | #endif | ||
386 | } | ||
387 | |||
388 | rover = block->next; // set roving pointer for next search | ||
389 | |||
390 | #ifdef INSTRUMENTED | ||
391 | inactive_memory += block->extra = block->size - size_orig; | ||
392 | if (tag >= PU_PURGELEVEL) | ||
393 | purgable_memory += size_orig; | ||
394 | else | ||
395 | active_memory += size_orig; | ||
396 | free_memory -= block->size; | ||
397 | #endif | ||
398 | } | ||
399 | } else { // We don't have enough contiguous free blocks | ||
400 | I_Error ("Z_Malloc: Failure trying to allocate %d bytes",(unsigned long) size); | ||
401 | rb->sleep(300); | ||
402 | } | ||
403 | |||
404 | #ifdef INSTRUMENTED | ||
405 | block->file = file; | ||
406 | block->line = line; | ||
407 | #endif | ||
408 | |||
409 | #ifdef ZONEIDCHECK | ||
410 | block->id = ZONEID; // signature required in block header | ||
411 | #endif | ||
412 | block->tag = tag; // tag | ||
413 | block->user = user; // user | ||
414 | block = (memblock_t *)((char *) block + HEADER_SIZE); | ||
415 | if (user) // if there is a user | ||
416 | *user = block; // set user to point to new block | ||
417 | |||
418 | #ifdef INSTRUMENTED | ||
419 | Z_PrintStats(); // print memory allocation stats | ||
420 | // scramble memory -- weed out any bugs | ||
421 | memset(block, gametic & 0xff, size); | ||
422 | #endif | ||
423 | return block; | ||
424 | } | ||
425 | |||
426 | void (Z_Free)(void *p | ||
427 | #ifdef INSTRUMENTED | ||
428 | , const char *file, int line | ||
429 | #endif | ||
430 | ) | ||
431 | { | ||
432 | #ifdef INSTRUMENTED | ||
433 | #ifdef CHECKHEAP | ||
434 | Z_CheckHeap(); | ||
435 | #endif | ||
436 | file_history[free_history][history_index[free_history]] = file; | ||
437 | line_history[free_history][history_index[free_history]++] = line; | ||
438 | history_index[free_history] &= ZONE_HISTORY-1; | ||
439 | #endif | ||
440 | |||
441 | if (p) | ||
442 | { | ||
443 | memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE); | ||
444 | |||
445 | #ifdef ZONEIDCHECK | ||
446 | if (block->id != ZONEID) | ||
447 | I_Error("Z_Free: freed a pointer without ZONEID" | ||
448 | #ifdef INSTRUMENTED | ||
449 | "\nSource: %s:%d" | ||
450 | "\nSource of malloc: %s:%d" | ||
451 | , file, line, block->file, block->line | ||
452 | #endif | ||
453 | ); | ||
454 | block->id = 0; // Nullify id so another free fails | ||
455 | #endif | ||
456 | |||
457 | #ifdef INSTRUMENTED | ||
458 | /* scramble memory -- weed out any bugs */ | ||
459 | memset(p, gametic & 0xff, block->size); | ||
460 | #endif | ||
461 | |||
462 | if (block->user) // Nullify user if one exists | ||
463 | *block->user = NULL; | ||
464 | |||
465 | { | ||
466 | |||
467 | #ifdef INSTRUMENTED | ||
468 | free_memory += block->size; | ||
469 | inactive_memory -= block->extra; | ||
470 | if (block->tag >= PU_PURGELEVEL) | ||
471 | purgable_memory -= block->size - block->extra; | ||
472 | else | ||
473 | active_memory -= block->size - block->extra; | ||
474 | #endif | ||
475 | |||
476 | block->tag = PU_FREE; // Mark block freed | ||
477 | |||
478 | if (block != zone) | ||
479 | { | ||
480 | other = block->prev; // Possibly merge with previous block | ||
481 | if (other->tag == PU_FREE) | ||
482 | { | ||
483 | if (rover == block) // Move back rover if it points at block | ||
484 | rover = other; | ||
485 | (other->next = block->next)->prev = other; | ||
486 | other->size += block->size + HEADER_SIZE; | ||
487 | block = other; | ||
488 | |||
489 | #ifdef INSTRUMENTED | ||
490 | inactive_memory -= HEADER_SIZE; | ||
491 | free_memory += HEADER_SIZE; | ||
492 | #endif | ||
493 | } | ||
494 | } | ||
495 | |||
496 | other = block->next; // Possibly merge with next block | ||
497 | if (other->tag == PU_FREE && other != zone) | ||
498 | { | ||
499 | if (rover == other) // Move back rover if it points at next block | ||
500 | rover = block; | ||
501 | (block->next = other->next)->prev = block; | ||
502 | block->size += other->size + HEADER_SIZE; | ||
503 | |||
504 | #ifdef INSTRUMENTED | ||
505 | inactive_memory -= HEADER_SIZE; | ||
506 | free_memory += HEADER_SIZE; | ||
507 | #endif | ||
508 | } | ||
509 | } | ||
510 | |||
511 | #ifdef INSTRUMENTED | ||
512 | Z_PrintStats(); // print memory allocation stats | ||
513 | #endif | ||
514 | } | ||
515 | } | ||
516 | |||
517 | void (Z_FreeTags)(int lowtag, int hightag | ||
518 | #ifdef INSTRUMENTED | ||
519 | , const char *file, int line | ||
520 | #endif | ||
521 | ) | ||
522 | { | ||
523 | /* cph - move rover to start of zone; we like to encourage static | ||
524 | * data to stay in one place, at the start of the heap | ||
525 | */ | ||
526 | memblock_t *block = rover = zone; | ||
527 | |||
528 | #ifdef HEAPDUMP | ||
529 | Z_DumpMemory(); | ||
530 | #endif | ||
531 | |||
532 | if (lowtag <= PU_FREE) | ||
533 | lowtag = PU_FREE+1; | ||
534 | |||
535 | do // Scan through list, searching for tags in range | ||
536 | if (block->tag >= lowtag && block->tag <= hightag) | ||
537 | { | ||
538 | memblock_t *prev = block->prev, *cur = block; | ||
539 | #ifdef INSTRUMENTED | ||
540 | (Z_Free)((char *) block + HEADER_SIZE, file, line); | ||
541 | #else | ||
542 | (Z_Free)((char *) block + HEADER_SIZE); | ||
543 | #endif | ||
544 | /* cph - be more careful here, we were skipping blocks! | ||
545 | * If the current block was not merged with the previous, | ||
546 | * cur is still a valid pointer, prev->next == cur, and cur is | ||
547 | * already free so skip to the next. | ||
548 | * If the current block was merged with the previous, | ||
549 | * the next block to analyse is prev->next. | ||
550 | * Note that the while() below does the actual step forward | ||
551 | */ | ||
552 | block = (prev->next == cur) ? cur : prev; | ||
553 | } | ||
554 | while ((block=block->next) != zone); | ||
555 | } | ||
556 | |||
557 | void (Z_ChangeTag)(void *ptr, int tag | ||
558 | #ifdef INSTRUMENTED | ||
559 | , const char *file, int line | ||
560 | #endif | ||
561 | ) | ||
562 | { | ||
563 | memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); | ||
564 | |||
565 | #ifdef INSTRUMENTED | ||
566 | #ifdef CHECKHEAP | ||
567 | Z_CheckHeap(); | ||
568 | #endif | ||
569 | #endif | ||
570 | |||
571 | #ifdef ZONEIDCHECK | ||
572 | if (block->id != ZONEID) | ||
573 | I_Error ("Z_ChangeTag: freed a pointer without ZONEID" | ||
574 | #ifdef INSTRUMENTED | ||
575 | "\nSource: %s:%d" | ||
576 | "\nSource of malloc: %s:%d" | ||
577 | , file, line, block->file, block->line | ||
578 | #endif | ||
579 | ); | ||
580 | |||
581 | if (tag >= PU_PURGELEVEL && !block->user) | ||
582 | I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n" | ||
583 | #ifdef INSTRUMENTED | ||
584 | "Source: %s:%d" | ||
585 | "\nSource of malloc: %s:%d" | ||
586 | , file, line, block->file, block->line | ||
587 | #endif | ||
588 | ); | ||
589 | |||
590 | #endif // ZONEIDCHECK | ||
591 | |||
592 | { | ||
593 | #ifdef INSTRUMENTED | ||
594 | if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL) | ||
595 | { | ||
596 | active_memory -= block->size - block->extra; | ||
597 | purgable_memory += block->size - block->extra; | ||
598 | } | ||
599 | else | ||
600 | if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL) | ||
601 | { | ||
602 | active_memory += block->size - block->extra; | ||
603 | purgable_memory -= block->size - block->extra; | ||
604 | } | ||
605 | #endif | ||
606 | } | ||
607 | block->tag = tag; | ||
608 | } | ||
609 | |||
610 | void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user | ||
611 | #ifdef INSTRUMENTED | ||
612 | , const char *file, int line | ||
613 | #endif | ||
614 | ) | ||
615 | { | ||
616 | void *p = (Z_Malloc)(n, tag, user DA(file, line)); | ||
617 | if (ptr) | ||
618 | { | ||
619 | memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); | ||
620 | memcpy(p, ptr, n <= block->size ? n : block->size); | ||
621 | (Z_Free)(ptr DA(file, line)); | ||
622 | if (user) // in case Z_Free nullified same user | ||
623 | *user=p; | ||
624 | } | ||
625 | return p; | ||
626 | } | ||
627 | |||
628 | void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user | ||
629 | #ifdef INSTRUMENTED | ||
630 | , const char *file, int line | ||
631 | #endif | ||
632 | ) | ||
633 | { | ||
634 | return | ||
635 | (n1*=n2) ? memset((Z_Malloc)(n1, tag, user DA(file, line)), 0, n1) : NULL; | ||
636 | } | ||
637 | |||
638 | char *(Z_Strdup)(const char *s, int tag, void **user | ||
639 | #ifdef INSTRUMENTED | ||
640 | , const char *file, int line | ||
641 | #endif | ||
642 | ) | ||
643 | { | ||
644 | return strcpy((Z_Malloc)(strlen(s)+1, tag, user DA(file, line)), s); | ||
645 | } | ||
646 | |||
647 | void (Z_CheckHeap)( | ||
648 | #ifdef INSTRUMENTED | ||
649 | const char *file, int line | ||
650 | #endif | ||
651 | ) | ||
652 | { | ||
653 | memblock_t *block = zone; // Start at base of zone mem | ||
654 | do // Consistency check (last node treated special) | ||
655 | if ((block->next != zone && | ||
656 | (memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) | ||
657 | || block->next->prev != block || block->prev->next != block) | ||
658 | I_Error("Z_ChkHp: B size %d touch %d\n", block+HEADER_SIZE+block->size, block->next | ||
659 | #ifdef INSTRUMENTED | ||
660 | "Source: %s:%d" | ||
661 | "\nSource of offending block: %s:%d" | ||
662 | , file, line, block->file, block->line | ||
663 | #endif | ||
664 | ); | ||
665 | while ((block=block->next) != zone); | ||
666 | } | ||