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