doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

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 }