Z_ZONE.C 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. //**************************************************************************
  2. //**
  3. //** z_zone.c : Heretic 2 : Raven Software, Corp.
  4. //**
  5. //** $RCSfile: z_zone.c,v $
  6. //** $Revision: 1.2 $
  7. //** $Date: 96/01/06 03:23:53 $
  8. //** $Author: bgokey $
  9. //**
  10. //**************************************************************************
  11. #include <stdlib.h>
  12. #include "h2def.h"
  13. /*
  14. ==============================================================================
  15. ZONE MEMORY ALLOCATION
  16. There is never any space between memblocks, and there will never be two
  17. contiguous free memblocks.
  18. The rover can be left pointing at a non-empty block
  19. It is of no value to free a cachable block, because it will get overwritten
  20. automatically if needed
  21. ==============================================================================
  22. */
  23. #define ZONEID 0x1d4a11
  24. typedef struct
  25. {
  26. int size; // total bytes malloced, including header
  27. memblock_t blocklist; // start / end cap for linked list
  28. memblock_t *rover;
  29. } memzone_t;
  30. memzone_t *mainzone;
  31. /*
  32. ========================
  33. =
  34. = Z_ClearZone
  35. =
  36. ========================
  37. */
  38. /*
  39. void Z_ClearZone (memzone_t *zone)
  40. {
  41. memblock_t *block;
  42. // set the entire zone to one free block
  43. zone->blocklist.next = zone->blocklist.prev = block =
  44. (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  45. zone->blocklist.user = (void *)zone;
  46. zone->blocklist.tag = PU_STATIC;
  47. zone->rover = block;
  48. block->prev = block->next = &zone->blocklist;
  49. block->user = NULL; // free block
  50. block->size = zone->size - sizeof(memzone_t);
  51. }
  52. */
  53. /*
  54. ========================
  55. =
  56. = Z_Init
  57. =
  58. ========================
  59. */
  60. void Z_Init (void)
  61. {
  62. memblock_t *block;
  63. int size;
  64. mainzone = (memzone_t *)I_ZoneBase (&size);
  65. mainzone->size = size;
  66. // set the entire zone to one free block
  67. mainzone->blocklist.next = mainzone->blocklist.prev = block =
  68. (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
  69. mainzone->blocklist.user = (void *)mainzone;
  70. mainzone->blocklist.tag = PU_STATIC;
  71. mainzone->rover = block;
  72. block->prev = block->next = &mainzone->blocklist;
  73. block->user = NULL; // free block
  74. block->size = mainzone->size - sizeof(memzone_t);
  75. }
  76. /*
  77. ========================
  78. =
  79. = Z_Free
  80. =
  81. ========================
  82. */
  83. void Z_Free (void *ptr)
  84. {
  85. memblock_t *block, *other;
  86. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  87. if (block->id != ZONEID)
  88. I_Error ("Z_Free: freed a pointer without ZONEID");
  89. if (block->user > (void **)0x100) // smaller values are not pointers
  90. *block->user = 0; // clear the user's mark
  91. block->user = NULL; // mark as free
  92. block->tag = 0;
  93. block->id = 0;
  94. other = block->prev;
  95. if (!other->user)
  96. { // merge with previous free block
  97. other->size += block->size;
  98. other->next = block->next;
  99. other->next->prev = other;
  100. if (block == mainzone->rover)
  101. mainzone->rover = other;
  102. block = other;
  103. }
  104. other = block->next;
  105. if (!other->user)
  106. { // merge the next free block onto the end
  107. block->size += other->size;
  108. block->next = other->next;
  109. block->next->prev = block;
  110. if (other == mainzone->rover)
  111. mainzone->rover = block;
  112. }
  113. }
  114. /*
  115. ========================
  116. =
  117. = Z_Malloc
  118. =
  119. = You can pass a NULL user if the tag is < PU_PURGELEVEL
  120. ========================
  121. */
  122. #define MINFRAGMENT 64
  123. void *Z_Malloc (int size, int tag, void *user)
  124. {
  125. int extra;
  126. memblock_t *start, *rover, *new, *base;
  127. //
  128. // scan through the block list looking for the first free block
  129. // of sufficient size, throwing out any purgable blocks along the way
  130. //
  131. size += sizeof(memblock_t); // account for size of block header
  132. //
  133. // if there is a free block behind the rover, back up over them
  134. //
  135. base = mainzone->rover;
  136. if (!base->prev->user)
  137. base = base->prev;
  138. rover = base;
  139. start = base->prev;
  140. do
  141. {
  142. if (rover == start) // scaned all the way around the list
  143. I_Error ("Z_Malloc: failed on allocation of %i bytes",size);
  144. if (rover->user)
  145. {
  146. if (rover->tag < PU_PURGELEVEL)
  147. // hit a block that can't be purged, so move base past it
  148. base = rover = rover->next;
  149. else
  150. {
  151. // free the rover block (adding the size to base)
  152. base = base->prev; // the rover can be the base block
  153. Z_Free ((byte *)rover+sizeof(memblock_t));
  154. base = base->next;
  155. rover = base->next;
  156. }
  157. }
  158. else
  159. rover = rover->next;
  160. } while (base->user || base->size < size);
  161. //
  162. // found a block big enough
  163. //
  164. extra = base->size - size;
  165. if (extra > MINFRAGMENT)
  166. { // there will be a free fragment after the allocated block
  167. new = (memblock_t *) ((byte *)base + size );
  168. new->size = extra;
  169. new->user = NULL; // free block
  170. new->tag = 0;
  171. new->prev = base;
  172. new->next = base->next;
  173. new->next->prev = new;
  174. base->next = new;
  175. base->size = size;
  176. }
  177. if (user)
  178. {
  179. base->user = user; // mark as an in use block
  180. *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
  181. }
  182. else
  183. {
  184. if (tag >= PU_PURGELEVEL)
  185. I_Error ("Z_Malloc: an owner is required for purgable blocks");
  186. base->user = (void *)2; // mark as in use, but unowned
  187. }
  188. base->tag = tag;
  189. mainzone->rover = base->next; // next allocation will start looking here
  190. base->id = ZONEID;
  191. return (void *) ((byte *)base + sizeof(memblock_t));
  192. }
  193. /*
  194. ========================
  195. =
  196. = Z_FreeTags
  197. =
  198. ========================
  199. */
  200. void Z_FreeTags (int lowtag, int hightag)
  201. {
  202. memblock_t *block, *next;
  203. for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
  204. ; block = next)
  205. {
  206. next = block->next; // get link before freeing
  207. if (!block->user)
  208. continue; // free block
  209. if (block->tag >= lowtag && block->tag <= hightag)
  210. Z_Free ( (byte *)block+sizeof(memblock_t));
  211. }
  212. }
  213. /*
  214. ========================
  215. =
  216. = Z_DumpHeap
  217. =
  218. ========================
  219. */
  220. /*
  221. void Z_DumpHeap (int lowtag, int hightag)
  222. {
  223. memblock_t *block;
  224. printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
  225. printf ("tag range: %i to %i\n",lowtag, hightag);
  226. for (block = mainzone->blocklist.next ; ; block = block->next)
  227. {
  228. if (block->tag >= lowtag && block->tag <= hightag)
  229. printf ("block:%p size:%7i user:%p tag:%3i\n",
  230. block, block->size, block->user, block->tag);
  231. if (block->next == &mainzone->blocklist)
  232. break; // all blocks have been hit
  233. if ( (byte *)block + block->size != (byte *)block->next)
  234. printf ("ERROR: block size does not touch the next block\n");
  235. if ( block->next->prev != block)
  236. printf ("ERROR: next block doesn't have proper back link\n");
  237. if (!block->user && !block->next->user)
  238. printf ("ERROR: two consecutive free blocks\n");
  239. }
  240. }
  241. */
  242. /*
  243. ========================
  244. =
  245. = Z_FileDumpHeap
  246. =
  247. ========================
  248. */
  249. /*
  250. void Z_FileDumpHeap (FILE *f)
  251. {
  252. memblock_t *block;
  253. fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone);
  254. for (block = mainzone->blocklist.next ; ; block = block->next)
  255. {
  256. fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
  257. block, block->size, block->user, block->tag);
  258. if (block->next == &mainzone->blocklist)
  259. break; // all blocks have been hit
  260. if ( (byte *)block + block->size != (byte *)block->next)
  261. fprintf (f,"ERROR: block size does not touch the next block\n");
  262. if ( block->next->prev != block)
  263. fprintf (f,"ERROR: next block doesn't have proper back link\n");
  264. if (!block->user && !block->next->user)
  265. fprintf (f,"ERROR: two consecutive free blocks\n");
  266. }
  267. }
  268. */
  269. /*
  270. ========================
  271. =
  272. = Z_CheckHeap
  273. =
  274. ========================
  275. */
  276. void Z_CheckHeap (void)
  277. {
  278. memblock_t *block;
  279. for (block = mainzone->blocklist.next ; ; block = block->next)
  280. {
  281. if (block->next == &mainzone->blocklist)
  282. break; // all blocks have been hit
  283. if ( (byte *)block + block->size != (byte *)block->next)
  284. I_Error ("Z_CheckHeap: block size does not touch the next block\n");
  285. if ( block->next->prev != block)
  286. I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
  287. if (!block->user && !block->next->user)
  288. I_Error ("Z_CheckHeap: two consecutive free blocks\n");
  289. }
  290. }
  291. /*
  292. ========================
  293. =
  294. = Z_ChangeTag
  295. =
  296. ========================
  297. */
  298. void Z_ChangeTag2 (void *ptr, int tag)
  299. {
  300. memblock_t *block;
  301. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  302. if (block->id != ZONEID)
  303. I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
  304. if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
  305. I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
  306. block->tag = tag;
  307. }
  308. /*
  309. ========================
  310. =
  311. = Z_FreeMemory
  312. =
  313. ========================
  314. */
  315. /*
  316. int Z_FreeMemory (void)
  317. {
  318. memblock_t *block;
  319. int free;
  320. free = 0;
  321. for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
  322. ; block = block->next)
  323. if (!block->user || block->tag >= PU_PURGELEVEL)
  324. free += block->size;
  325. return free;
  326. }
  327. */