Annotation of quakeworld/client/zone.c, revision 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.