zone.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // Z_zone.c
  16. #include "quakedef.h"
  17. #define DYNAMIC_SIZE 0x20000
  18. #define ZONEID 0x1d4a11
  19. #define MINFRAGMENT 64
  20. typedef struct memblock_s
  21. {
  22. int size; // including the header and possibly tiny fragments
  23. int tag; // a tag of 0 is a free block
  24. int id; // should be ZONEID
  25. struct memblock_s *next, *prev;
  26. int pad; // pad to 64 bit boundary
  27. } memblock_t;
  28. typedef struct
  29. {
  30. int size; // total bytes malloced, including header
  31. memblock_t blocklist; // start / end cap for linked list
  32. memblock_t *rover;
  33. } memzone_t;
  34. void Cache_FreeLow (int new_low_hunk);
  35. void Cache_FreeHigh (int new_high_hunk);
  36. /*
  37. ==============================================================================
  38. ZONE MEMORY ALLOCATION
  39. There is never any space between memblocks, and there will never be two
  40. contiguous free memblocks.
  41. The rover can be left pointing at a non-empty block
  42. The zone calls are pretty much only used for small strings and structures,
  43. all big things are allocated on the hunk.
  44. ==============================================================================
  45. */
  46. memzone_t *mainzone;
  47. void Z_ClearZone (memzone_t *zone, int size);
  48. /*
  49. ========================
  50. Z_ClearZone
  51. ========================
  52. */
  53. void Z_ClearZone (memzone_t *zone, int size)
  54. {
  55. memblock_t *block;
  56. // set the entire zone to one free block
  57. zone->blocklist.next = zone->blocklist.prev = block =
  58. (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  59. zone->blocklist.tag = 1; // in use block
  60. zone->blocklist.id = 0;
  61. zone->blocklist.size = 0;
  62. zone->rover = block;
  63. block->prev = block->next = &zone->blocklist;
  64. block->tag = 0; // free block
  65. block->id = ZONEID;
  66. block->size = size - sizeof(memzone_t);
  67. }
  68. /*
  69. ========================
  70. Z_Free
  71. ========================
  72. */
  73. void Z_Free (void *ptr)
  74. {
  75. memblock_t *block, *other;
  76. if (!ptr)
  77. Sys_Error ("Z_Free: NULL pointer");
  78. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  79. if (block->id != ZONEID)
  80. Sys_Error ("Z_Free: freed a pointer without ZONEID");
  81. if (block->tag == 0)
  82. Sys_Error ("Z_Free: freed a freed pointer");
  83. block->tag = 0; // mark as free
  84. other = block->prev;
  85. if (!other->tag)
  86. { // merge with previous free block
  87. other->size += block->size;
  88. other->next = block->next;
  89. other->next->prev = other;
  90. if (block == mainzone->rover)
  91. mainzone->rover = other;
  92. block = other;
  93. }
  94. other = block->next;
  95. if (!other->tag)
  96. { // merge the next free block onto the end
  97. block->size += other->size;
  98. block->next = other->next;
  99. block->next->prev = block;
  100. if (other == mainzone->rover)
  101. mainzone->rover = block;
  102. }
  103. }
  104. /*
  105. ========================
  106. Z_Malloc
  107. ========================
  108. */
  109. void *Z_Malloc (int size)
  110. {
  111. void *buf;
  112. Z_CheckHeap (); // DEBUG
  113. buf = Z_TagMalloc (size, 1);
  114. if (!buf)
  115. Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
  116. Q_memset (buf, 0, size);
  117. return buf;
  118. }
  119. void *Z_TagMalloc (int size, int tag)
  120. {
  121. int extra;
  122. memblock_t *start, *rover, *new, *base;
  123. if (!tag)
  124. Sys_Error ("Z_TagMalloc: tried to use a 0 tag");
  125. //
  126. // scan through the block list looking for the first free block
  127. // of sufficient size
  128. //
  129. size += sizeof(memblock_t); // account for size of block header
  130. size += 4; // space for memory trash tester
  131. size = (size + 7) & ~7; // align to 8-byte boundary
  132. base = rover = mainzone->rover;
  133. start = base->prev;
  134. do
  135. {
  136. if (rover == start) // scaned all the way around the list
  137. return NULL;
  138. if (rover->tag)
  139. base = rover = rover->next;
  140. else
  141. rover = rover->next;
  142. } while (base->tag || base->size < size);
  143. //
  144. // found a block big enough
  145. //
  146. extra = base->size - size;
  147. if (extra > MINFRAGMENT)
  148. { // there will be a free fragment after the allocated block
  149. new = (memblock_t *) ((byte *)base + size );
  150. new->size = extra;
  151. new->tag = 0; // free block
  152. new->prev = base;
  153. new->id = ZONEID;
  154. new->next = base->next;
  155. new->next->prev = new;
  156. base->next = new;
  157. base->size = size;
  158. }
  159. base->tag = tag; // no longer a free block
  160. mainzone->rover = base->next; // next allocation will start looking here
  161. base->id = ZONEID;
  162. // marker for memory trash testing
  163. *(int *)((byte *)base + base->size - 4) = ZONEID;
  164. return (void *) ((byte *)base + sizeof(memblock_t));
  165. }
  166. /*
  167. ========================
  168. Z_Print
  169. ========================
  170. */
  171. void Z_Print (memzone_t *zone)
  172. {
  173. memblock_t *block;
  174. Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
  175. for (block = zone->blocklist.next ; ; block = block->next)
  176. {
  177. Con_Printf ("block:%p size:%7i tag:%3i\n",
  178. block, block->size, block->tag);
  179. if (block->next == &zone->blocklist)
  180. break; // all blocks have been hit
  181. if ( (byte *)block + block->size != (byte *)block->next)
  182. Con_Printf ("ERROR: block size does not touch the next block\n");
  183. if ( block->next->prev != block)
  184. Con_Printf ("ERROR: next block doesn't have proper back link\n");
  185. if (!block->tag && !block->next->tag)
  186. Con_Printf ("ERROR: two consecutive free blocks\n");
  187. }
  188. }
  189. /*
  190. ========================
  191. Z_CheckHeap
  192. ========================
  193. */
  194. void Z_CheckHeap (void)
  195. {
  196. memblock_t *block;
  197. for (block = mainzone->blocklist.next ; ; block = block->next)
  198. {
  199. if (block->next == &mainzone->blocklist)
  200. break; // all blocks have been hit
  201. if ( (byte *)block + block->size != (byte *)block->next)
  202. Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");
  203. if ( block->next->prev != block)
  204. Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
  205. if (!block->tag && !block->next->tag)
  206. Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");
  207. }
  208. }
  209. //============================================================================
  210. #define HUNK_SENTINAL 0x1df001ed
  211. typedef struct
  212. {
  213. int sentinal;
  214. int size; // including sizeof(hunk_t), -1 = not allocated
  215. char name[8];
  216. } hunk_t;
  217. byte *hunk_base;
  218. int hunk_size;
  219. int hunk_low_used;
  220. int hunk_high_used;
  221. qboolean hunk_tempactive;
  222. int hunk_tempmark;
  223. void R_FreeTextures (void);
  224. /*
  225. ==============
  226. Hunk_Check
  227. Run consistancy and sentinal trahing checks
  228. ==============
  229. */
  230. void Hunk_Check (void)
  231. {
  232. hunk_t *h;
  233. for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )
  234. {
  235. if (h->sentinal != HUNK_SENTINAL)
  236. Sys_Error ("Hunk_Check: trahsed sentinal");
  237. if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
  238. Sys_Error ("Hunk_Check: bad size");
  239. h = (hunk_t *)((byte *)h+h->size);
  240. }
  241. }
  242. /*
  243. ==============
  244. Hunk_Print
  245. If "all" is specified, every single allocation is printed.
  246. Otherwise, allocations with the same name will be totaled up before printing.
  247. ==============
  248. */
  249. void Hunk_Print (qboolean all)
  250. {
  251. hunk_t *h, *next, *endlow, *starthigh, *endhigh;
  252. int count, sum;
  253. int totalblocks;
  254. char name[9];
  255. name[8] = 0;
  256. count = 0;
  257. sum = 0;
  258. totalblocks = 0;
  259. h = (hunk_t *)hunk_base;
  260. endlow = (hunk_t *)(hunk_base + hunk_low_used);
  261. starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
  262. endhigh = (hunk_t *)(hunk_base + hunk_size);
  263. Con_Printf (" :%8i total hunk size\n", hunk_size);
  264. Con_Printf ("-------------------------\n");
  265. while (1)
  266. {
  267. //
  268. // skip to the high hunk if done with low hunk
  269. //
  270. if ( h == endlow )
  271. {
  272. Con_Printf ("-------------------------\n");
  273. Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);
  274. Con_Printf ("-------------------------\n");
  275. h = starthigh;
  276. }
  277. //
  278. // if totally done, break
  279. //
  280. if ( h == endhigh )
  281. break;
  282. //
  283. // run consistancy checks
  284. //
  285. if (h->sentinal != HUNK_SENTINAL)
  286. Sys_Error ("Hunk_Check: trahsed sentinal");
  287. if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
  288. Sys_Error ("Hunk_Check: bad size");
  289. next = (hunk_t *)((byte *)h+h->size);
  290. count++;
  291. totalblocks++;
  292. sum += h->size;
  293. //
  294. // print the single block
  295. //
  296. memcpy (name, h->name, 8);
  297. if (all)
  298. Con_Printf ("%8p :%8i %8s\n",h, h->size, name);
  299. //
  300. // print the total
  301. //
  302. if (next == endlow || next == endhigh ||
  303. strncmp (h->name, next->name, 8) )
  304. {
  305. if (!all)
  306. Con_Printf (" :%8i %8s (TOTAL)\n",sum, name);
  307. count = 0;
  308. sum = 0;
  309. }
  310. h = next;
  311. }
  312. Con_Printf ("-------------------------\n");
  313. Con_Printf ("%8i total blocks\n", totalblocks);
  314. }
  315. /*
  316. ===================
  317. Hunk_AllocName
  318. ===================
  319. */
  320. void *Hunk_AllocName (int size, char *name)
  321. {
  322. hunk_t *h;
  323. #ifdef PARANOID
  324. Hunk_Check ();
  325. #endif
  326. if (size < 0)
  327. Sys_Error ("Hunk_Alloc: bad size: %i", size);
  328. size = sizeof(hunk_t) + ((size+15)&~15);
  329. if (hunk_size - hunk_low_used - hunk_high_used < size)
  330. // Sys_Error ("Hunk_Alloc: failed on %i bytes",size);
  331. #ifdef _WIN32
  332. Sys_Error ("Not enough RAM allocated. Try starting using \"-heapsize 16000\" on the QuakeWorld command line.");
  333. #else
  334. Sys_Error ("Not enough RAM allocated. Try starting using \"-mem 16\" on the QuakeWorld command line.");
  335. #endif
  336. h = (hunk_t *)(hunk_base + hunk_low_used);
  337. hunk_low_used += size;
  338. Cache_FreeLow (hunk_low_used);
  339. memset (h, 0, size);
  340. h->size = size;
  341. h->sentinal = HUNK_SENTINAL;
  342. Q_strncpy (h->name, name, 8);
  343. return (void *)(h+1);
  344. }
  345. /*
  346. ===================
  347. Hunk_Alloc
  348. ===================
  349. */
  350. void *Hunk_Alloc (int size)
  351. {
  352. return Hunk_AllocName (size, "unknown");
  353. }
  354. int Hunk_LowMark (void)
  355. {
  356. return hunk_low_used;
  357. }
  358. void Hunk_FreeToLowMark (int mark)
  359. {
  360. if (mark < 0 || mark > hunk_low_used)
  361. Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
  362. memset (hunk_base + mark, 0, hunk_low_used - mark);
  363. hunk_low_used = mark;
  364. }
  365. int Hunk_HighMark (void)
  366. {
  367. if (hunk_tempactive)
  368. {
  369. hunk_tempactive = false;
  370. Hunk_FreeToHighMark (hunk_tempmark);
  371. }
  372. return hunk_high_used;
  373. }
  374. void Hunk_FreeToHighMark (int mark)
  375. {
  376. if (hunk_tempactive)
  377. {
  378. hunk_tempactive = false;
  379. Hunk_FreeToHighMark (hunk_tempmark);
  380. }
  381. if (mark < 0 || mark > hunk_high_used)
  382. Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
  383. memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
  384. hunk_high_used = mark;
  385. }
  386. /*
  387. ===================
  388. Hunk_HighAllocName
  389. ===================
  390. */
  391. void *Hunk_HighAllocName (int size, char *name)
  392. {
  393. hunk_t *h;
  394. if (size < 0)
  395. Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
  396. if (hunk_tempactive)
  397. {
  398. Hunk_FreeToHighMark (hunk_tempmark);
  399. hunk_tempactive = false;
  400. }
  401. #ifdef PARANOID
  402. Hunk_Check ();
  403. #endif
  404. size = sizeof(hunk_t) + ((size+15)&~15);
  405. if (hunk_size - hunk_low_used - hunk_high_used < size)
  406. {
  407. Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
  408. return NULL;
  409. }
  410. hunk_high_used += size;
  411. Cache_FreeHigh (hunk_high_used);
  412. h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
  413. memset (h, 0, size);
  414. h->size = size;
  415. h->sentinal = HUNK_SENTINAL;
  416. Q_strncpy (h->name, name, 8);
  417. return (void *)(h+1);
  418. }
  419. /*
  420. =================
  421. Hunk_TempAlloc
  422. Return space from the top of the hunk
  423. =================
  424. */
  425. void *Hunk_TempAlloc (int size)
  426. {
  427. void *buf;
  428. size = (size+15)&~15;
  429. if (hunk_tempactive)
  430. {
  431. Hunk_FreeToHighMark (hunk_tempmark);
  432. hunk_tempactive = false;
  433. }
  434. hunk_tempmark = Hunk_HighMark ();
  435. buf = Hunk_HighAllocName (size, "temp");
  436. hunk_tempactive = true;
  437. return buf;
  438. }
  439. /*
  440. ===============================================================================
  441. CACHE MEMORY
  442. ===============================================================================
  443. */
  444. typedef struct cache_system_s
  445. {
  446. int size; // including this header
  447. cache_user_t *user;
  448. char name[16];
  449. struct cache_system_s *prev, *next;
  450. struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
  451. } cache_system_t;
  452. cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
  453. cache_system_t cache_head;
  454. /*
  455. ===========
  456. Cache_Move
  457. ===========
  458. */
  459. void Cache_Move ( cache_system_t *c)
  460. {
  461. cache_system_t *new;
  462. // we are clearing up space at the bottom, so only allocate it late
  463. new = Cache_TryAlloc (c->size, true);
  464. if (new)
  465. {
  466. // Con_Printf ("cache_move ok\n");
  467. Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
  468. new->user = c->user;
  469. Q_memcpy (new->name, c->name, sizeof(new->name));
  470. Cache_Free (c->user);
  471. new->user->data = (void *)(new+1);
  472. }
  473. else
  474. {
  475. // Con_Printf ("cache_move failed\n");
  476. Cache_Free (c->user); // tough luck...
  477. }
  478. }
  479. /*
  480. ============
  481. Cache_FreeLow
  482. Throw things out until the hunk can be expanded to the given point
  483. ============
  484. */
  485. void Cache_FreeLow (int new_low_hunk)
  486. {
  487. cache_system_t *c;
  488. while (1)
  489. {
  490. c = cache_head.next;
  491. if (c == &cache_head)
  492. return; // nothing in cache at all
  493. if ((byte *)c >= hunk_base + new_low_hunk)
  494. return; // there is space to grow the hunk
  495. Cache_Move ( c ); // reclaim the space
  496. }
  497. }
  498. /*
  499. ============
  500. Cache_FreeHigh
  501. Throw things out until the hunk can be expanded to the given point
  502. ============
  503. */
  504. void Cache_FreeHigh (int new_high_hunk)
  505. {
  506. cache_system_t *c, *prev;
  507. prev = NULL;
  508. while (1)
  509. {
  510. c = cache_head.prev;
  511. if (c == &cache_head)
  512. return; // nothing in cache at all
  513. if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
  514. return; // there is space to grow the hunk
  515. if (c == prev)
  516. Cache_Free (c->user); // didn't move out of the way
  517. else
  518. {
  519. Cache_Move (c); // try to move it
  520. prev = c;
  521. }
  522. }
  523. }
  524. void Cache_UnlinkLRU (cache_system_t *cs)
  525. {
  526. if (!cs->lru_next || !cs->lru_prev)
  527. Sys_Error ("Cache_UnlinkLRU: NULL link");
  528. cs->lru_next->lru_prev = cs->lru_prev;
  529. cs->lru_prev->lru_next = cs->lru_next;
  530. cs->lru_prev = cs->lru_next = NULL;
  531. }
  532. void Cache_MakeLRU (cache_system_t *cs)
  533. {
  534. if (cs->lru_next || cs->lru_prev)
  535. Sys_Error ("Cache_MakeLRU: active link");
  536. cache_head.lru_next->lru_prev = cs;
  537. cs->lru_next = cache_head.lru_next;
  538. cs->lru_prev = &cache_head;
  539. cache_head.lru_next = cs;
  540. }
  541. /*
  542. ============
  543. Cache_TryAlloc
  544. Looks for a free block of memory between the high and low hunk marks
  545. Size should already include the header and padding
  546. ============
  547. */
  548. cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
  549. {
  550. cache_system_t *cs, *new;
  551. // is the cache completely empty?
  552. if (!nobottom && cache_head.prev == &cache_head)
  553. {
  554. if (hunk_size - hunk_high_used - hunk_low_used < size)
  555. Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
  556. new = (cache_system_t *) (hunk_base + hunk_low_used);
  557. memset (new, 0, sizeof(*new));
  558. new->size = size;
  559. cache_head.prev = cache_head.next = new;
  560. new->prev = new->next = &cache_head;
  561. Cache_MakeLRU (new);
  562. return new;
  563. }
  564. // search from the bottom up for space
  565. new = (cache_system_t *) (hunk_base + hunk_low_used);
  566. cs = cache_head.next;
  567. do
  568. {
  569. if (!nobottom || cs != cache_head.next)
  570. {
  571. if ( (byte *)cs - (byte *)new >= size)
  572. { // found space
  573. memset (new, 0, sizeof(*new));
  574. new->size = size;
  575. new->next = cs;
  576. new->prev = cs->prev;
  577. cs->prev->next = new;
  578. cs->prev = new;
  579. Cache_MakeLRU (new);
  580. return new;
  581. }
  582. }
  583. // continue looking
  584. new = (cache_system_t *)((byte *)cs + cs->size);
  585. cs = cs->next;
  586. } while (cs != &cache_head);
  587. // try to allocate one at the very end
  588. if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
  589. {
  590. memset (new, 0, sizeof(*new));
  591. new->size = size;
  592. new->next = &cache_head;
  593. new->prev = cache_head.prev;
  594. cache_head.prev->next = new;
  595. cache_head.prev = new;
  596. Cache_MakeLRU (new);
  597. return new;
  598. }
  599. return NULL; // couldn't allocate
  600. }
  601. /*
  602. ============
  603. Cache_Flush
  604. Throw everything out, so new data will be demand cached
  605. ============
  606. */
  607. void Cache_Flush (void)
  608. {
  609. while (cache_head.next != &cache_head)
  610. Cache_Free ( cache_head.next->user ); // reclaim the space
  611. }
  612. /*
  613. ============
  614. Cache_Print
  615. ============
  616. */
  617. void Cache_Print (void)
  618. {
  619. cache_system_t *cd;
  620. for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
  621. {
  622. Con_Printf ("%8i : %s\n", cd->size, cd->name);
  623. }
  624. }
  625. /*
  626. ============
  627. Cache_Report
  628. ============
  629. */
  630. void Cache_Report (void)
  631. {
  632. Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
  633. }
  634. /*
  635. ============
  636. Cache_Compact
  637. ============
  638. */
  639. void Cache_Compact (void)
  640. {
  641. }
  642. /*
  643. ============
  644. Cache_Init
  645. ============
  646. */
  647. void Cache_Init (void)
  648. {
  649. cache_head.next = cache_head.prev = &cache_head;
  650. cache_head.lru_next = cache_head.lru_prev = &cache_head;
  651. Cmd_AddCommand ("flush", Cache_Flush);
  652. }
  653. /*
  654. ==============
  655. Cache_Free
  656. Frees the memory and removes it from the LRU list
  657. ==============
  658. */
  659. void Cache_Free (cache_user_t *c)
  660. {
  661. cache_system_t *cs;
  662. if (!c->data)
  663. Sys_Error ("Cache_Free: not allocated");
  664. cs = ((cache_system_t *)c->data) - 1;
  665. cs->prev->next = cs->next;
  666. cs->next->prev = cs->prev;
  667. cs->next = cs->prev = NULL;
  668. c->data = NULL;
  669. Cache_UnlinkLRU (cs);
  670. }
  671. /*
  672. ==============
  673. Cache_Check
  674. ==============
  675. */
  676. void *Cache_Check (cache_user_t *c)
  677. {
  678. cache_system_t *cs;
  679. if (!c->data)
  680. return NULL;
  681. cs = ((cache_system_t *)c->data) - 1;
  682. // move to head of LRU
  683. Cache_UnlinkLRU (cs);
  684. Cache_MakeLRU (cs);
  685. return c->data;
  686. }
  687. /*
  688. ==============
  689. Cache_Alloc
  690. ==============
  691. */
  692. void *Cache_Alloc (cache_user_t *c, int size, char *name)
  693. {
  694. cache_system_t *cs;
  695. if (c->data)
  696. Sys_Error ("Cache_Alloc: allready allocated");
  697. if (size <= 0)
  698. Sys_Error ("Cache_Alloc: size %i", size);
  699. size = (size + sizeof(cache_system_t) + 15) & ~15;
  700. // find memory for it
  701. while (1)
  702. {
  703. cs = Cache_TryAlloc (size, false);
  704. if (cs)
  705. {
  706. strncpy (cs->name, name, sizeof(cs->name)-1);
  707. c->data = (void *)(cs+1);
  708. cs->user = c;
  709. break;
  710. }
  711. // free the least recently used cahedat
  712. if (cache_head.lru_prev == &cache_head)
  713. Sys_Error ("Cache_Alloc: out of memory");
  714. // not enough memory at all
  715. Cache_Free ( cache_head.lru_prev->user );
  716. }
  717. return Cache_Check (c);
  718. }
  719. //============================================================================
  720. /*
  721. ========================
  722. Memory_Init
  723. ========================
  724. */
  725. void Memory_Init (void *buf, int size)
  726. {
  727. int p;
  728. int zonesize = DYNAMIC_SIZE;
  729. hunk_base = buf;
  730. hunk_size = size;
  731. hunk_low_used = 0;
  732. hunk_high_used = 0;
  733. Cache_Init ();
  734. p = COM_CheckParm ("-zone");
  735. if (p)
  736. {
  737. if (p < com_argc-1)
  738. zonesize = Q_atoi (com_argv[p+1]) * 1024;
  739. else
  740. Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
  741. }
  742. mainzone = Hunk_AllocName ( zonesize, "zone" );
  743. Z_ClearZone (mainzone, zonesize);
  744. }