z_zone.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "Precompiled.h"
  21. #include "z_zone.h"
  22. #include "i_system.h"
  23. #include "doomdef.h"
  24. #include "globaldata.h"
  25. //
  26. // ZONE MEMORY ALLOCATION
  27. //
  28. // There is never any space between memblocks,
  29. // and there will never be two contiguous free memblocks.
  30. // The rover can be left pointing at a non-empty block.
  31. //
  32. // It is of no value to free a cachable block,
  33. // because it will get overwritten automatically if needed.
  34. //
  35. #define ZONEID 0x1d4a11
  36. //
  37. // Z_ClearZone
  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 =
  44. zone->blocklist.prev =
  45. block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  46. zone->blocklist.user = (void **)zone;
  47. zone->blocklist.tag = PU_STATIC;
  48. zone->rover = block;
  49. block->prev = block->next = &zone->blocklist;
  50. // NULL indicates a free block.
  51. block->user = NULL;
  52. block->size = zone->size - sizeof(memzone_t);
  53. }
  54. void *I_ZoneBase( int *size )
  55. {
  56. enum
  57. {
  58. HEAP_SIZE = 15 * 1024 * 1024 // SMF - was 10 * 1024 * 1024
  59. };
  60. *size = HEAP_SIZE;
  61. return malloc( HEAP_SIZE );
  62. }
  63. //
  64. // Z_Init
  65. //
  66. void Z_Init (void)
  67. {
  68. memblock_t* block;
  69. int size;
  70. ::g->mainzone = (memzone_t *)I_ZoneBase (&size);
  71. memset( ::g->mainzone, 0, size );
  72. ::g->mainzone->size = size;
  73. // set the entire zone to one free block
  74. ::g->mainzone->blocklist.next =
  75. ::g->mainzone->blocklist.prev =
  76. block = (memblock_t *)( (byte *)::g->mainzone + sizeof(memzone_t) );
  77. ::g->mainzone->blocklist.user = (void **)::g->mainzone;
  78. ::g->mainzone->blocklist.tag = PU_STATIC;
  79. ::g->mainzone->rover = block;
  80. block->prev = block->next = &::g->mainzone->blocklist;
  81. // NULL indicates a free block.
  82. block->user = NULL;
  83. block->size = ::g->mainzone->size - sizeof(memzone_t);
  84. }
  85. int NumAlloc = 0;
  86. //
  87. // Z_Free
  88. //
  89. void Z_Free (void* ptr)
  90. {
  91. memblock_t* block;
  92. memblock_t* other;
  93. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  94. NumAlloc -= block->size;
  95. if (block->id != ZONEID)
  96. I_Error ("Z_Free: freed a pointer without ZONEID");
  97. if (block->user > (void **)0x100)
  98. {
  99. // smaller values are not pointers
  100. // Note: OS-dependend?
  101. // clear the user's mark
  102. *block->user = 0;
  103. }
  104. // mark as free
  105. block->user = NULL;
  106. block->tag = 0;
  107. block->id = 0;
  108. other = block->prev;
  109. if (!other->user)
  110. {
  111. // merge with previous free block
  112. other->size += block->size;
  113. other->next = block->next;
  114. other->next->prev = other;
  115. if (block == ::g->mainzone->rover)
  116. ::g->mainzone->rover = other;
  117. block = other;
  118. }
  119. other = block->next;
  120. if (!other->user)
  121. {
  122. // merge the next free block onto the end
  123. block->size += other->size;
  124. block->next = other->next;
  125. block->next->prev = block;
  126. if (other == ::g->mainzone->rover)
  127. ::g->mainzone->rover = block;
  128. }
  129. }
  130. //
  131. // Z_Malloc
  132. // You can pass a NULL user if the tag is < PU_PURGELEVEL.
  133. //
  134. #define MINFRAGMENT 64
  135. void*
  136. Z_Malloc
  137. ( int size,
  138. int tag,
  139. void* user )
  140. {
  141. int extra;
  142. memblock_t* start;
  143. memblock_t* rover;
  144. memblock_t* newblock;
  145. memblock_t* base;
  146. NumAlloc += size;
  147. size = (size + 3) & ~3;
  148. // scan through the block list,
  149. // looking for the first free block
  150. // of sufficient size,
  151. // throwing out any purgable blocks along the way.
  152. // account for size of block header
  153. size += sizeof(memblock_t);
  154. // if there is a free block behind the rover,
  155. // back up over them
  156. base = ::g->mainzone->rover;
  157. if (!base->prev->user)
  158. base = base->prev;
  159. rover = base;
  160. start = base->prev;
  161. do
  162. {
  163. if (rover == start)
  164. {
  165. // scanned all the way around the list
  166. I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
  167. }
  168. if (rover->user)
  169. {
  170. if (rover->tag < PU_PURGELEVEL)
  171. {
  172. // hit a block that can't be purged,
  173. // so move base past it
  174. base = rover = rover->next;
  175. }
  176. else
  177. {
  178. // free the rover block (adding the size to base)
  179. // the rover can be the base block
  180. base = base->prev;
  181. Z_Free ((byte *)rover+sizeof(memblock_t));
  182. base = base->next;
  183. rover = base->next;
  184. }
  185. }
  186. else
  187. rover = rover->next;
  188. } while (base->user || base->size < size);
  189. // found a block big enough
  190. extra = base->size - size;
  191. if (extra > MINFRAGMENT)
  192. {
  193. // there will be a free fragment after the allocated block
  194. newblock = (memblock_t *) ((byte *)base + size );
  195. newblock->size = extra;
  196. // NULL indicates free block.
  197. newblock->user = NULL;
  198. newblock->tag = 0;
  199. newblock->prev = base;
  200. newblock->next = base->next;
  201. newblock->next->prev = newblock;
  202. base->next = newblock;
  203. base->size = size;
  204. }
  205. if (user)
  206. {
  207. // mark as an in use block
  208. base->user = (void**)user;
  209. *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
  210. }
  211. else
  212. {
  213. if (tag >= PU_PURGELEVEL)
  214. I_Error ("Z_Malloc: an owner is required for purgable blocks");
  215. // mark as in use, but unowned
  216. base->user = (void **)2;
  217. }
  218. base->tag = tag;
  219. // next allocation will start looking here
  220. ::g->mainzone->rover = base->next;
  221. base->id = ZONEID;
  222. return (void *) ((byte *)base + sizeof(memblock_t));
  223. }
  224. //
  225. // Z_FreeTags
  226. //
  227. void
  228. Z_FreeTags
  229. ( int lowtag,
  230. int hightag )
  231. {
  232. memblock_t* block;
  233. memblock_t* next;
  234. for (block = ::g->mainzone->blocklist.next ;
  235. block != &::g->mainzone->blocklist ;
  236. block = next)
  237. {
  238. // get link before freeing
  239. next = block->next;
  240. // free block?
  241. if (!block->user)
  242. continue;
  243. if (block->tag >= lowtag && block->tag <= hightag)
  244. Z_Free ( (byte *)block+sizeof(memblock_t));
  245. }
  246. }
  247. //
  248. // Z_DumpHeap
  249. // Note: TFileDumpHeap( stdout ) ?
  250. //
  251. void
  252. Z_DumpHeap
  253. ( int lowtag,
  254. int hightag )
  255. {
  256. memblock_t* block;
  257. I_Printf ("zone size: %i location: %p\n",
  258. ::g->mainzone->size,::g->mainzone);
  259. I_Printf ("tag range: %i to %i\n",
  260. lowtag, hightag);
  261. for (block = ::g->mainzone->blocklist.next ; ; block = block->next)
  262. {
  263. if (block->tag >= lowtag && block->tag <= hightag)
  264. I_Printf ("block:%p size:%7i user:%p tag:%3i\n",
  265. block, block->size, block->user, block->tag);
  266. if (block->next == &::g->mainzone->blocklist)
  267. {
  268. // all blocks have been hit
  269. break;
  270. }
  271. if ( (byte *)block + block->size != (byte *)block->next)
  272. I_Printf ("ERROR: block size does not touch the next block\n");
  273. if ( block->next->prev != block)
  274. I_Printf ("ERROR: next block doesn't have proper back link\n");
  275. if (!block->user && !block->next->user)
  276. I_Printf ("ERROR: two consecutive free blocks\n");
  277. }
  278. }
  279. //
  280. // Z_FileDumpHeap
  281. //
  282. void Z_FileDumpHeap (FILE* f)
  283. {
  284. memblock_t* block;
  285. fprintf (f,"zone size: %i location: %p\n",::g->mainzone->size,::g->mainzone);
  286. for (block = ::g->mainzone->blocklist.next ; ; block = block->next)
  287. {
  288. fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
  289. block, block->size, block->user, block->tag);
  290. if (block->next == &::g->mainzone->blocklist)
  291. {
  292. // all blocks have been hit
  293. break;
  294. }
  295. if ( (byte *)block + block->size != (byte *)block->next)
  296. fprintf (f,"ERROR: block size does not touch the next block\n");
  297. if ( block->next->prev != block)
  298. fprintf (f,"ERROR: next block doesn't have proper back link\n");
  299. if (!block->user && !block->next->user)
  300. fprintf (f,"ERROR: two consecutive free blocks\n");
  301. }
  302. }
  303. //
  304. // Z_CheckHeap
  305. //
  306. void Z_CheckHeap (void)
  307. {
  308. memblock_t* block;
  309. for (block = ::g->mainzone->blocklist.next ; ; block = block->next)
  310. {
  311. if (block->next == &::g->mainzone->blocklist)
  312. {
  313. // all blocks have been hit
  314. break;
  315. }
  316. if ( (byte *)block + block->size != (byte *)block->next)
  317. I_Error ("Z_CheckHeap: block size does not touch the next block\n");
  318. if ( block->next->prev != block)
  319. I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
  320. if (!block->user && !block->next->user)
  321. I_Error ("Z_CheckHeap: two consecutive free blocks\n");
  322. }
  323. }
  324. //
  325. // Z_ChangeTag
  326. //
  327. void
  328. Z_ChangeTag2
  329. ( void* ptr,
  330. int tag )
  331. {
  332. memblock_t* block;
  333. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  334. if (block->id != ZONEID)
  335. I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
  336. if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
  337. I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
  338. block->tag = tag;
  339. }
  340. void Z_ChangeTag2( void** pp, int tag ) { Z_ChangeTag2( *pp, tag ); }
  341. //
  342. // Z_FreeMemory
  343. //
  344. int Z_FreeMemory (void)
  345. {
  346. memblock_t* block;
  347. int free;
  348. free = 0;
  349. for (block = ::g->mainzone->blocklist.next ;
  350. block != &::g->mainzone->blocklist;
  351. block = block->next)
  352. {
  353. if (!block->user || block->tag >= PU_PURGELEVEL)
  354. free += block->size;
  355. }
  356. return free;
  357. }
  358. /*
  359. bool MallocForLump( int lump, unsigned int size, void **data, int tag )
  360. {
  361. *data = Z_Malloc( size, tag, 0 );
  362. return true;
  363. }
  364. */