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