zone.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  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 0xc000
  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. h = (hunk_t *)(hunk_base + hunk_low_used);
  332. hunk_low_used += size;
  333. Cache_FreeLow (hunk_low_used);
  334. memset (h, 0, size);
  335. h->size = size;
  336. h->sentinal = HUNK_SENTINAL;
  337. Q_strncpy (h->name, name, 8);
  338. return (void *)(h+1);
  339. }
  340. /*
  341. ===================
  342. Hunk_Alloc
  343. ===================
  344. */
  345. void *Hunk_Alloc (int size)
  346. {
  347. return Hunk_AllocName (size, "unknown");
  348. }
  349. int Hunk_LowMark (void)
  350. {
  351. return hunk_low_used;
  352. }
  353. void Hunk_FreeToLowMark (int mark)
  354. {
  355. if (mark < 0 || mark > hunk_low_used)
  356. Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
  357. memset (hunk_base + mark, 0, hunk_low_used - mark);
  358. hunk_low_used = mark;
  359. }
  360. int Hunk_HighMark (void)
  361. {
  362. if (hunk_tempactive)
  363. {
  364. hunk_tempactive = false;
  365. Hunk_FreeToHighMark (hunk_tempmark);
  366. }
  367. return hunk_high_used;
  368. }
  369. void Hunk_FreeToHighMark (int mark)
  370. {
  371. if (hunk_tempactive)
  372. {
  373. hunk_tempactive = false;
  374. Hunk_FreeToHighMark (hunk_tempmark);
  375. }
  376. if (mark < 0 || mark > hunk_high_used)
  377. Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
  378. memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
  379. hunk_high_used = mark;
  380. }
  381. /*
  382. ===================
  383. Hunk_HighAllocName
  384. ===================
  385. */
  386. void *Hunk_HighAllocName (int size, char *name)
  387. {
  388. hunk_t *h;
  389. if (size < 0)
  390. Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
  391. if (hunk_tempactive)
  392. {
  393. Hunk_FreeToHighMark (hunk_tempmark);
  394. hunk_tempactive = false;
  395. }
  396. #ifdef PARANOID
  397. Hunk_Check ();
  398. #endif
  399. size = sizeof(hunk_t) + ((size+15)&~15);
  400. if (hunk_size - hunk_low_used - hunk_high_used < size)
  401. {
  402. Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
  403. return NULL;
  404. }
  405. hunk_high_used += size;
  406. Cache_FreeHigh (hunk_high_used);
  407. h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
  408. memset (h, 0, size);
  409. h->size = size;
  410. h->sentinal = HUNK_SENTINAL;
  411. Q_strncpy (h->name, name, 8);
  412. return (void *)(h+1);
  413. }
  414. /*
  415. =================
  416. Hunk_TempAlloc
  417. Return space from the top of the hunk
  418. =================
  419. */
  420. void *Hunk_TempAlloc (int size)
  421. {
  422. void *buf;
  423. size = (size+15)&~15;
  424. if (hunk_tempactive)
  425. {
  426. Hunk_FreeToHighMark (hunk_tempmark);
  427. hunk_tempactive = false;
  428. }
  429. hunk_tempmark = Hunk_HighMark ();
  430. buf = Hunk_HighAllocName (size, "temp");
  431. hunk_tempactive = true;
  432. return buf;
  433. }
  434. /*
  435. ===============================================================================
  436. CACHE MEMORY
  437. ===============================================================================
  438. */
  439. typedef struct cache_system_s
  440. {
  441. int size; // including this header
  442. cache_user_t *user;
  443. char name[16];
  444. struct cache_system_s *prev, *next;
  445. struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
  446. } cache_system_t;
  447. cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
  448. cache_system_t cache_head;
  449. /*
  450. ===========
  451. Cache_Move
  452. ===========
  453. */
  454. void Cache_Move ( cache_system_t *c)
  455. {
  456. cache_system_t *new;
  457. // we are clearing up space at the bottom, so only allocate it late
  458. new = Cache_TryAlloc (c->size, true);
  459. if (new)
  460. {
  461. // Con_Printf ("cache_move ok\n");
  462. Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
  463. new->user = c->user;
  464. Q_memcpy (new->name, c->name, sizeof(new->name));
  465. Cache_Free (c->user);
  466. new->user->data = (void *)(new+1);
  467. }
  468. else
  469. {
  470. // Con_Printf ("cache_move failed\n");
  471. Cache_Free (c->user); // tough luck...
  472. }
  473. }
  474. /*
  475. ============
  476. Cache_FreeLow
  477. Throw things out until the hunk can be expanded to the given point
  478. ============
  479. */
  480. void Cache_FreeLow (int new_low_hunk)
  481. {
  482. cache_system_t *c;
  483. while (1)
  484. {
  485. c = cache_head.next;
  486. if (c == &cache_head)
  487. return; // nothing in cache at all
  488. if ((byte *)c >= hunk_base + new_low_hunk)
  489. return; // there is space to grow the hunk
  490. Cache_Move ( c ); // reclaim the space
  491. }
  492. }
  493. /*
  494. ============
  495. Cache_FreeHigh
  496. Throw things out until the hunk can be expanded to the given point
  497. ============
  498. */
  499. void Cache_FreeHigh (int new_high_hunk)
  500. {
  501. cache_system_t *c, *prev;
  502. prev = NULL;
  503. while (1)
  504. {
  505. c = cache_head.prev;
  506. if (c == &cache_head)
  507. return; // nothing in cache at all
  508. if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
  509. return; // there is space to grow the hunk
  510. if (c == prev)
  511. Cache_Free (c->user); // didn't move out of the way
  512. else
  513. {
  514. Cache_Move (c); // try to move it
  515. prev = c;
  516. }
  517. }
  518. }
  519. void Cache_UnlinkLRU (cache_system_t *cs)
  520. {
  521. if (!cs->lru_next || !cs->lru_prev)
  522. Sys_Error ("Cache_UnlinkLRU: NULL link");
  523. cs->lru_next->lru_prev = cs->lru_prev;
  524. cs->lru_prev->lru_next = cs->lru_next;
  525. cs->lru_prev = cs->lru_next = NULL;
  526. }
  527. void Cache_MakeLRU (cache_system_t *cs)
  528. {
  529. if (cs->lru_next || cs->lru_prev)
  530. Sys_Error ("Cache_MakeLRU: active link");
  531. cache_head.lru_next->lru_prev = cs;
  532. cs->lru_next = cache_head.lru_next;
  533. cs->lru_prev = &cache_head;
  534. cache_head.lru_next = cs;
  535. }
  536. /*
  537. ============
  538. Cache_TryAlloc
  539. Looks for a free block of memory between the high and low hunk marks
  540. Size should already include the header and padding
  541. ============
  542. */
  543. cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
  544. {
  545. cache_system_t *cs, *new;
  546. // is the cache completely empty?
  547. if (!nobottom && cache_head.prev == &cache_head)
  548. {
  549. if (hunk_size - hunk_high_used - hunk_low_used < size)
  550. Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
  551. new = (cache_system_t *) (hunk_base + hunk_low_used);
  552. memset (new, 0, sizeof(*new));
  553. new->size = size;
  554. cache_head.prev = cache_head.next = new;
  555. new->prev = new->next = &cache_head;
  556. Cache_MakeLRU (new);
  557. return new;
  558. }
  559. // search from the bottom up for space
  560. new = (cache_system_t *) (hunk_base + hunk_low_used);
  561. cs = cache_head.next;
  562. do
  563. {
  564. if (!nobottom || cs != cache_head.next)
  565. {
  566. if ( (byte *)cs - (byte *)new >= size)
  567. { // found space
  568. memset (new, 0, sizeof(*new));
  569. new->size = size;
  570. new->next = cs;
  571. new->prev = cs->prev;
  572. cs->prev->next = new;
  573. cs->prev = new;
  574. Cache_MakeLRU (new);
  575. return new;
  576. }
  577. }
  578. // continue looking
  579. new = (cache_system_t *)((byte *)cs + cs->size);
  580. cs = cs->next;
  581. } while (cs != &cache_head);
  582. // try to allocate one at the very end
  583. if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
  584. {
  585. memset (new, 0, sizeof(*new));
  586. new->size = size;
  587. new->next = &cache_head;
  588. new->prev = cache_head.prev;
  589. cache_head.prev->next = new;
  590. cache_head.prev = new;
  591. Cache_MakeLRU (new);
  592. return new;
  593. }
  594. return NULL; // couldn't allocate
  595. }
  596. /*
  597. ============
  598. Cache_Flush
  599. Throw everything out, so new data will be demand cached
  600. ============
  601. */
  602. void Cache_Flush (void)
  603. {
  604. while (cache_head.next != &cache_head)
  605. Cache_Free ( cache_head.next->user ); // reclaim the space
  606. }
  607. /*
  608. ============
  609. Cache_Print
  610. ============
  611. */
  612. void Cache_Print (void)
  613. {
  614. cache_system_t *cd;
  615. for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
  616. {
  617. Con_Printf ("%8i : %s\n", cd->size, cd->name);
  618. }
  619. }
  620. /*
  621. ============
  622. Cache_Report
  623. ============
  624. */
  625. void Cache_Report (void)
  626. {
  627. Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
  628. }
  629. /*
  630. ============
  631. Cache_Compact
  632. ============
  633. */
  634. void Cache_Compact (void)
  635. {
  636. }
  637. /*
  638. ============
  639. Cache_Init
  640. ============
  641. */
  642. void Cache_Init (void)
  643. {
  644. cache_head.next = cache_head.prev = &cache_head;
  645. cache_head.lru_next = cache_head.lru_prev = &cache_head;
  646. Cmd_AddCommand ("flush", Cache_Flush);
  647. }
  648. /*
  649. ==============
  650. Cache_Free
  651. Frees the memory and removes it from the LRU list
  652. ==============
  653. */
  654. void Cache_Free (cache_user_t *c)
  655. {
  656. cache_system_t *cs;
  657. if (!c->data)
  658. Sys_Error ("Cache_Free: not allocated");
  659. cs = ((cache_system_t *)c->data) - 1;
  660. cs->prev->next = cs->next;
  661. cs->next->prev = cs->prev;
  662. cs->next = cs->prev = NULL;
  663. c->data = NULL;
  664. Cache_UnlinkLRU (cs);
  665. }
  666. /*
  667. ==============
  668. Cache_Check
  669. ==============
  670. */
  671. void *Cache_Check (cache_user_t *c)
  672. {
  673. cache_system_t *cs;
  674. if (!c->data)
  675. return NULL;
  676. cs = ((cache_system_t *)c->data) - 1;
  677. // move to head of LRU
  678. Cache_UnlinkLRU (cs);
  679. Cache_MakeLRU (cs);
  680. return c->data;
  681. }
  682. /*
  683. ==============
  684. Cache_Alloc
  685. ==============
  686. */
  687. void *Cache_Alloc (cache_user_t *c, int size, char *name)
  688. {
  689. cache_system_t *cs;
  690. if (c->data)
  691. Sys_Error ("Cache_Alloc: allready allocated");
  692. if (size <= 0)
  693. Sys_Error ("Cache_Alloc: size %i", size);
  694. size = (size + sizeof(cache_system_t) + 15) & ~15;
  695. // find memory for it
  696. while (1)
  697. {
  698. cs = Cache_TryAlloc (size, false);
  699. if (cs)
  700. {
  701. strncpy (cs->name, name, sizeof(cs->name)-1);
  702. c->data = (void *)(cs+1);
  703. cs->user = c;
  704. break;
  705. }
  706. // free the least recently used cahedat
  707. if (cache_head.lru_prev == &cache_head)
  708. Sys_Error ("Cache_Alloc: out of memory");
  709. // not enough memory at all
  710. Cache_Free ( cache_head.lru_prev->user );
  711. }
  712. return Cache_Check (c);
  713. }
  714. //============================================================================
  715. /*
  716. ========================
  717. Memory_Init
  718. ========================
  719. */
  720. void Memory_Init (void *buf, int size)
  721. {
  722. int p;
  723. int zonesize = DYNAMIC_SIZE;
  724. hunk_base = buf;
  725. hunk_size = size;
  726. hunk_low_used = 0;
  727. hunk_high_used = 0;
  728. Cache_Init ();
  729. p = COM_CheckParm ("-zone");
  730. if (p)
  731. {
  732. if (p < com_argc-1)
  733. zonesize = Q_atoi (com_argv[p+1]) * 1024;
  734. else
  735. Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
  736. }
  737. mainzone = Hunk_AllocName (zonesize, "zone" );
  738. Z_ClearZone (mainzone, zonesize);
  739. }