z_zone.c (5965B)
1 #include <stdlib.h> 2 3 #include "z_zone.h" 4 #include "i_system.h" 5 #include "doomdef.h" 6 7 #define ZONEID 0x1d4a11 8 #define MINFRAGMENT 64 9 10 typedef struct memzone_t memzone_t; 11 12 struct memzone_t { 13 int size; 14 memblock_t mainblock; 15 memblock_t* rover; 16 }; 17 18 memzone_t* mainzone_g; 19 20 void 21 Z_Init() 22 { 23 mainzone_g = malloc(4 * 1024 * 1024); 24 mainzone_g->size = 4 * 1024 * 1024; 25 mainzone_g->mainblock.user = (void*)mainzone_g; 26 mainzone_g->mainblock.tag = PU_STATIC; 27 mainzone_g->mainblock.prev = 28 mainzone_g->mainblock.next = 29 mainzone_g->rover = (memblock_t*)((uchar*)mainzone_g + sizeof(*mainzone_g)); 30 mainzone_g->rover->prev = 31 mainzone_g->rover->next = &mainzone_g->mainblock; 32 mainzone_g->rover->user = NULL; 33 mainzone_g->rover->size = mainzone_g->size - sizeof(*mainzone_g); 34 } 35 36 void 37 Z_Free(void* ptr) 38 { 39 memblock_t* block; 40 memblock_t* other; 41 42 block = (memblock_t*)((uchar*)ptr - sizeof(memblock_t)); 43 if (block->id != ZONEID) 44 I_Error("Z_Free: freed a pointer without ZONEID"); 45 if (block->user > (void**)0x100) 46 *block->user = 0; 47 block->user = NULL; 48 block->tag = 0; 49 block->id = 0; 50 other = block->prev; 51 if (!other->user) { 52 other->size += block->size; 53 other->next = block->next; 54 other->next->prev = other; 55 if (block == mainzone_g->rover) 56 mainzone_g->rover = other; 57 block = other; 58 } 59 other = block->next; 60 if (!other->user) { 61 block->size += other->size; 62 block->next = other->next; 63 block->next->prev = block; 64 if (other == mainzone_g->rover) mainzone_g->rover = block; 65 } 66 } 67 68 void* 69 Z_Malloc(int size, int tag, void* user) 70 { 71 memblock_t* start, *rover, *newblock, *base; 72 int extra; 73 74 size = (size + 3) & ~3; 75 size += sizeof(memblock_t); 76 base = mainzone_g->rover; 77 if (!base->prev->user) 78 base = base->prev; 79 rover = base; 80 start = base->prev; 81 do { 82 if (rover == start) 83 I_Error("Z_Malloc: failed on allocation of %i bytes", size); 84 if (rover->user) { 85 if (rover->tag < PU_PURGELEVEL) 86 base = rover = rover->next; 87 else { 88 base = base->prev; 89 Z_Free((byte*)rover + sizeof(memblock_t)); 90 base = base->next; 91 rover = base->next; 92 } 93 } 94 else 95 rover = rover->next; 96 } while (base->user || base->size < size); 97 extra = base->size - size; 98 if (extra > MINFRAGMENT) { 99 newblock = (memblock_t*)((uchar*)base + size); 100 newblock->size = extra; 101 newblock->user = NULL; 102 newblock->tag = 0; 103 newblock->prev = base; 104 newblock->next = base->next; 105 newblock->next->prev = newblock; 106 base->next = newblock; 107 base->size = size; 108 } 109 if (user) { 110 base->user = user; 111 *(void**)user = (void*)((byte*)base + sizeof(memblock_t)); 112 } else { 113 if (tag >= PU_PURGELEVEL) 114 I_Error("Z_Malloc: an owner is required for purgable blocks"); 115 base->user = (void*)2; 116 } 117 base->tag = tag; 118 mainzone_g->rover = base->next; 119 base->id = ZONEID; 120 return (void*)((byte*)base + sizeof(memblock_t)); 121 } 122 123 void 124 Z_FreeTags(int lowtag, int hightag) 125 { 126 memblock_t* block; 127 memblock_t* next; 128 129 for (block = mainzone_g->mainblock.next; block != &mainzone_g->mainblock; block = next) { 130 next = block->next; 131 if (!block->user) 132 continue; 133 if (block->tag >= lowtag && block->tag <= hightag) 134 Z_Free((byte*)block+sizeof(memblock_t)); 135 } 136 } 137 138 void 139 Z_DumpHeap(int lowtag, int hightag) 140 { 141 memblock_t* block; 142 143 printf("zone size: %i location: %p\n", mainzone_g->size, (void*)mainzone_g); 144 printf("tag range: %i to %i\n", lowtag, hightag); 145 for (block = mainzone_g->mainblock.next;; block = block->next) { 146 if (block->tag >= lowtag && block->tag <= hightag) printf("block:%p size:%7i user:%p tag:%3i\n", (void*)block, block->size, (void*)block->user, block->tag); 147 if (block->next == &mainzone_g->mainblock) break; 148 if ((byte*)block + block->size != (byte*)block->next) printf("ERROR: block size does not touch the next block\n"); 149 if (block->next->prev != block) printf("ERROR: next block doesn't have proper back link\n"); 150 if (!block->user && !block->next->user) printf("ERROR: two consecutive free blocks\n"); 151 } 152 } 153 154 void 155 Z_FileDumpHeap(FILE* f) 156 { 157 memblock_t* block; 158 159 fprintf(f, "zone size: %i location: %p\n", mainzone_g->size, (void*)mainzone_g); 160 for (block = mainzone_g->mainblock.next;; block = block->next) { 161 fprintf(f, "block:%p size:%7i user:%p tag:%3i\n", (void*)block, block->size, (void*)block->user, block->tag); 162 if (block->next == &mainzone_g->mainblock) break; 163 if ((byte*)block + block->size != (byte*)block->next) fprintf(f, "ERROR: block size does not touch the next block\n"); 164 if (block->next->prev != block) fprintf(f, "ERROR: next block doesn't have proper back link\n"); 165 if (!block->user && !block->next->user) fprintf(f, "ERROR: two consecutive free blocks\n"); 166 } 167 } 168 169 void 170 Z_CheckHeap() 171 { 172 memblock_t* block; 173 174 for (block = mainzone_g->mainblock.next;; block = block->next) { 175 if (block->next == &mainzone_g->mainblock) break; 176 if ((byte*)block + block->size != (byte*)block->next) I_Error("Z_CheckHeap: block size does not touch the next block\n"); 177 if (block->next->prev != block) I_Error("Z_CheckHeap: next block doesn't have proper back link\n"); 178 if (!block->user && !block->next->user) I_Error("Z_CheckHeap: two consecutive free blocks\n"); 179 } 180 } 181 182 void 183 Z_ChangeTag2(void* ptr, int tag) 184 { 185 memblock_t* block; 186 187 block = (memblock_t*)((byte*)ptr - sizeof(memblock_t)); 188 if (block->id != ZONEID) I_Error("Z_ChangeTag: freed a pointer without ZONEID"); 189 if (tag >= PU_PURGELEVEL &&(unsigned long)block->user < 0x100) I_Error("Z_ChangeTag: an owner is required for purgable blocks"); 190 block->tag = tag; 191 } 192 193 int 194 Z_FreeMemory() 195 { 196 memblock_t* block; 197 int free; 198 199 free = 0; 200 for (block = mainzone_g->mainblock.next; block != &mainzone_g->mainblock; block = block->next) 201 if (!block->user || block->tag >= PU_PURGELEVEL) 202 free += block->size; 203 return free; 204 }