Annotation of quakeworld/client/zone.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.