Z_ZONE.C 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Z_zone.c
  2. #include <stdlib.h>
  3. #include "DoomDef.h"
  4. /*
  5. ==============================================================================
  6. ZONE MEMORY ALLOCATION
  7. There is never any space between memblocks, and there will never be two
  8. contiguous free memblocks.
  9. The rover can be left pointing at a non-empty block
  10. It is of no value to free a cachable block, because it will get overwritten
  11. automatically if needed
  12. ==============================================================================
  13. */
  14. #define ZONEID 0x1d4a11
  15. typedef struct
  16. {
  17. int size; // total bytes malloced, including header
  18. memblock_t blocklist; // start / end cap for linked list
  19. memblock_t *rover;
  20. } memzone_t;
  21. boolean MallocFailureOk;
  22. memzone_t *mainzone;
  23. /*
  24. ========================
  25. =
  26. = Z_ClearZone
  27. =
  28. ========================
  29. */
  30. void Z_ClearZone (memzone_t *zone)
  31. {
  32. memblock_t *block;
  33. // set the entire zone to one free block
  34. zone->blocklist.next = zone->blocklist.prev = block =
  35. (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  36. zone->blocklist.user = (void *)zone;
  37. zone->blocklist.tag = PU_STATIC;
  38. zone->rover = block;
  39. block->prev = block->next = &zone->blocklist;
  40. block->user = NULL; // free block
  41. block->size = zone->size - sizeof(memzone_t);
  42. }
  43. /*
  44. ========================
  45. =
  46. = Z_Init
  47. =
  48. ========================
  49. */
  50. void Z_Init (void)
  51. {
  52. memblock_t *block;
  53. int size;
  54. MallocFailureOk = false;
  55. mainzone = (memzone_t *)I_ZoneBase (&size);
  56. mainzone->size = size;
  57. // set the entire zone to one free block
  58. mainzone->blocklist.next = mainzone->blocklist.prev = block =
  59. (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
  60. mainzone->blocklist.user = (void *)mainzone;
  61. mainzone->blocklist.tag = PU_STATIC;
  62. mainzone->rover = block;
  63. block->prev = block->next = &mainzone->blocklist;
  64. block->user = NULL; // free block
  65. block->size = mainzone->size - sizeof(memzone_t);
  66. }
  67. /*
  68. ========================
  69. =
  70. = Z_Free
  71. =
  72. ========================
  73. */
  74. void Z_Free (void *ptr)
  75. {
  76. memblock_t *block, *other;
  77. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  78. if (block->id != ZONEID)
  79. I_Error ("Z_Free: freed a pointer without ZONEID");
  80. if (block->user > (void **)0x100) // smaller values are not pointers
  81. *block->user = 0; // clear the user's mark
  82. block->user = NULL; // mark as free
  83. block->tag = 0;
  84. block->id = 0;
  85. other = block->prev;
  86. if (!other->user)
  87. { // merge with previous free block
  88. other->size += block->size;
  89. other->next = block->next;
  90. other->next->prev = other;
  91. if (block == mainzone->rover)
  92. mainzone->rover = other;
  93. block = other;
  94. }
  95. other = block->next;
  96. if (!other->user)
  97. { // merge the next free block onto the end
  98. block->size += other->size;
  99. block->next = other->next;
  100. block->next->prev = block;
  101. if (other == mainzone->rover)
  102. mainzone->rover = block;
  103. }
  104. }
  105. /*
  106. ========================
  107. =
  108. = Z_Malloc
  109. =
  110. = You can pass a NULL user if the tag is < PU_PURGELEVEL
  111. ========================
  112. */
  113. #define MINFRAGMENT 64
  114. void *Z_Malloc (int size, int tag, void *user)
  115. {
  116. int extra;
  117. memblock_t *start, *rover, *new, *base;
  118. //
  119. // scan through the block list looking for the first free block
  120. // of sufficient size, throwing out any purgable blocks along the way
  121. //
  122. size += sizeof(memblock_t); // account for size of block header
  123. //
  124. // if there is a free block behind the rover, back up over them
  125. //
  126. base = mainzone->rover;
  127. if (!base->prev->user)
  128. base = base->prev;
  129. rover = base;
  130. start = base->prev;
  131. do
  132. {
  133. if(rover == start)
  134. { // Scanned all the way around the list
  135. if(MallocFailureOk == true)
  136. {
  137. return NULL;
  138. }
  139. else
  140. {
  141. I_Error("Z_Malloc: failed on allocation of %i bytes", size);
  142. }
  143. }
  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. void Z_DumpHeap (int lowtag, int hightag)
  221. {
  222. memblock_t *block;
  223. printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
  224. printf ("tag range: %i to %i\n",lowtag, hightag);
  225. for (block = mainzone->blocklist.next ; ; block = block->next)
  226. {
  227. if (block->tag >= lowtag && block->tag <= hightag)
  228. printf ("block:%p size:%7i user:%p tag:%3i\n",
  229. block, block->size, block->user, block->tag);
  230. if (block->next == &mainzone->blocklist)
  231. break; // all blocks have been hit
  232. if ( (byte *)block + block->size != (byte *)block->next)
  233. printf ("ERROR: block size does not touch the next block\n");
  234. if ( block->next->prev != block)
  235. printf ("ERROR: next block doesn't have proper back link\n");
  236. if (!block->user && !block->next->user)
  237. printf ("ERROR: two consecutive free blocks\n");
  238. }
  239. }
  240. /*
  241. ========================
  242. =
  243. = Z_FileDumpHeap
  244. =
  245. ========================
  246. */
  247. void Z_FileDumpHeap (FILE *f)
  248. {
  249. memblock_t *block;
  250. fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone);
  251. for (block = mainzone->blocklist.next ; ; block = block->next)
  252. {
  253. fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
  254. block, block->size, block->user, block->tag);
  255. if (block->next == &mainzone->blocklist)
  256. break; // all blocks have been hit
  257. if ( (byte *)block + block->size != (byte *)block->next)
  258. fprintf (f,"ERROR: block size does not touch the next block\n");
  259. if ( block->next->prev != block)
  260. fprintf (f,"ERROR: next block doesn't have proper back link\n");
  261. if (!block->user && !block->next->user)
  262. fprintf (f,"ERROR: two consecutive free blocks\n");
  263. }
  264. }
  265. /*
  266. ========================
  267. =
  268. = Z_CheckHeap
  269. =
  270. ========================
  271. */
  272. void Z_CheckHeap (void)
  273. {
  274. memblock_t *block;
  275. for (block = mainzone->blocklist.next ; ; block = block->next)
  276. {
  277. if (block->next == &mainzone->blocklist)
  278. break; // all blocks have been hit
  279. if ( (byte *)block + block->size != (byte *)block->next)
  280. I_Error ("Z_CheckHeap: block size does not touch the next block\n");
  281. if ( block->next->prev != block)
  282. I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
  283. if (!block->user && !block->next->user)
  284. I_Error ("Z_CheckHeap: two consecutive free blocks\n");
  285. }
  286. }
  287. /*
  288. ========================
  289. =
  290. = Z_ChangeTag
  291. =
  292. ========================
  293. */
  294. void Z_ChangeTag2 (void *ptr, int tag)
  295. {
  296. memblock_t *block;
  297. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  298. if (block->id != ZONEID)
  299. I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
  300. if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
  301. I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
  302. block->tag = tag;
  303. }
  304. /*
  305. ========================
  306. =
  307. = Z_FreeMemory
  308. =
  309. ========================
  310. */
  311. int Z_FreeMemory (void)
  312. {
  313. memblock_t *block;
  314. int free;
  315. free = 0;
  316. for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
  317. ; block = block->next)
  318. if (!block->user || block->tag >= PU_PURGELEVEL)
  319. free += block->size;
  320. return free;
  321. }