mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-20 09:21:09 +00:00
new cache allocation scheme. still a couple warts, but at least now there's something to work with, and more importantly, there won't be cache movement anywhere near as often.
This commit is contained in:
parent
e5b972529b
commit
4cab5b90e6
2 changed files with 252 additions and 246 deletions
|
@ -135,8 +135,8 @@ void *Cache_Alloc (cache_user_t *c, int size, const char *name);
|
|||
void Cache_Report (void);
|
||||
void Cache_Add (cache_user_t *c, void *object, cache_loader_t loader);
|
||||
void Cache_Remove (cache_user_t *c);
|
||||
void *Cache_Get (cache_user_t *c);
|
||||
void *Cache_TryGet (cache_user_t *c);
|
||||
void *Cache_Get (cache_user_t *c);
|
||||
void Cache_Release (cache_user_t *c);
|
||||
int Cache_ReadLock (cache_user_t *c);
|
||||
|
||||
|
|
496
libs/util/zone.c
496
libs/util/zone.c
|
@ -50,7 +50,8 @@ static __attribute__ ((used)) const char rcsid[] =
|
|||
#include "compat.h"
|
||||
|
||||
static void Cache_FreeLow (int new_low_hunk);
|
||||
static void Cache_FreeHigh (int new_high_hunk);
|
||||
static void Cache_Profile (void);
|
||||
static qboolean Cache_FreeLRU (void);
|
||||
|
||||
#define ZONEID 0x1d4a11
|
||||
#define HUNK_SENTINAL 0x1df001ed
|
||||
|
@ -405,6 +406,30 @@ Hunk_Print (qboolean all)
|
|||
Sys_Printf ("%8i total blocks\n", totalblocks);
|
||||
}
|
||||
*/
|
||||
static void
|
||||
Hunk_FreeToHighMark (int mark)
|
||||
{
|
||||
if (hunk_tempactive) {
|
||||
hunk_tempactive = false;
|
||||
Hunk_FreeToHighMark (hunk_tempmark);
|
||||
}
|
||||
if (mark < 0 || mark > hunk_high_used)
|
||||
Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
|
||||
memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
|
||||
hunk_high_used = mark;
|
||||
}
|
||||
|
||||
static int
|
||||
Hunk_HighMark (void)
|
||||
{
|
||||
if (hunk_tempactive) {
|
||||
hunk_tempactive = false;
|
||||
Hunk_FreeToHighMark (hunk_tempmark);
|
||||
}
|
||||
|
||||
return hunk_high_used;
|
||||
}
|
||||
|
||||
VISIBLE void *
|
||||
Hunk_AllocName (int size, const char *name)
|
||||
{
|
||||
|
@ -419,11 +444,17 @@ Hunk_AllocName (int size, const char *name)
|
|||
|
||||
size = sizeof (hunk_t) + ((size + 15) & ~15);
|
||||
|
||||
if (hunk_size - hunk_low_used - hunk_high_used < size)
|
||||
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||
Hunk_HighMark();
|
||||
Cache_FreeLRU ();
|
||||
}
|
||||
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||
Cache_Profile ();
|
||||
Sys_Error
|
||||
("Not enough RAM allocated. Try starting using \"-mem 16\" on "
|
||||
"the %s command line. (%d - %d - %d < %d)",
|
||||
PROGRAM, hunk_size, hunk_low_used, hunk_high_used, size);
|
||||
}
|
||||
|
||||
h = (hunk_t *) (hunk_base + hunk_low_used);
|
||||
hunk_low_used += size;
|
||||
|
@ -460,37 +491,11 @@ Hunk_FreeToLowMark (int mark)
|
|||
hunk_low_used = mark;
|
||||
}
|
||||
|
||||
static void
|
||||
Hunk_FreeToHighMark (int mark)
|
||||
{
|
||||
if (hunk_tempactive) {
|
||||
hunk_tempactive = false;
|
||||
Hunk_FreeToHighMark (hunk_tempmark);
|
||||
}
|
||||
if (mark < 0 || mark > hunk_high_used)
|
||||
Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
|
||||
memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
|
||||
hunk_high_used = mark;
|
||||
}
|
||||
|
||||
static int
|
||||
Hunk_HighMark (void)
|
||||
{
|
||||
if (hunk_tempactive) {
|
||||
hunk_tempactive = false;
|
||||
Hunk_FreeToHighMark (hunk_tempmark);
|
||||
}
|
||||
|
||||
return hunk_high_used;
|
||||
}
|
||||
|
||||
static void *
|
||||
Hunk_HighAllocName (int size, const char *name)
|
||||
Hunk_HighAlloc (int size)
|
||||
{
|
||||
hunk_t *h;
|
||||
|
||||
if (size < 0)
|
||||
Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
|
||||
Sys_Error ("Hunk_HighAlloc: bad size: %i", size);
|
||||
|
||||
if (hunk_tempactive) {
|
||||
Hunk_FreeToHighMark (hunk_tempmark);
|
||||
|
@ -500,7 +505,7 @@ Hunk_HighAllocName (int size, const char *name)
|
|||
Hunk_Check ();
|
||||
#endif
|
||||
|
||||
size = sizeof (hunk_t) + ((size + 15) & ~15);
|
||||
size = ((size + 15) & ~15);
|
||||
|
||||
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||
Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size);
|
||||
|
@ -508,15 +513,8 @@ Hunk_HighAllocName (int size, const char *name)
|
|||
}
|
||||
|
||||
hunk_high_used += size;
|
||||
Cache_FreeHigh (hunk_high_used);
|
||||
|
||||
h = (hunk_t *) (hunk_base + hunk_size - hunk_high_used);
|
||||
|
||||
h->size = size;
|
||||
h->sentinal = HUNK_SENTINAL;
|
||||
strncpy (h->name, name, 8);
|
||||
|
||||
return (void *) (h + 1);
|
||||
return (void *) (hunk_base + hunk_size - hunk_high_used);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -541,7 +539,7 @@ Hunk_TempAlloc (int size)
|
|||
|
||||
hunk_tempmark = Hunk_HighMark ();
|
||||
|
||||
buf = Hunk_HighAllocName (size, "temp");
|
||||
buf = Hunk_HighAlloc (size);
|
||||
|
||||
hunk_tempactive = true;
|
||||
|
||||
|
@ -550,19 +548,19 @@ Hunk_TempAlloc (int size)
|
|||
|
||||
/* CACHE MEMORY */
|
||||
|
||||
typedef struct cache_system_s {
|
||||
cache_user_t *user;
|
||||
typedef struct cache_system_s cache_system_t;
|
||||
struct cache_system_s {
|
||||
cache_system_t *prev, *next;
|
||||
cache_system_t *lru_prev, *lru_next; // for LRU flushing
|
||||
char name[16];
|
||||
int size; // including this header
|
||||
size_t size; // including this header
|
||||
int readlock;
|
||||
struct cache_system_s *prev, *next;
|
||||
struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
|
||||
} cache_system_t;
|
||||
cache_user_t *user;
|
||||
};
|
||||
|
||||
static cache_system_t cache_head;
|
||||
|
||||
static cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
|
||||
static void Cache_Profile (void);
|
||||
static cache_system_t *Cache_TryAlloc (size_t size, qboolean nobottom);
|
||||
|
||||
static void
|
||||
Cache_Move (cache_system_t * c)
|
||||
|
@ -597,46 +595,22 @@ Cache_FreeLow (int new_low_hunk)
|
|||
cache_system_t *c;
|
||||
|
||||
while (1) {
|
||||
c = cache_head.next;
|
||||
c = cache_head.prev;
|
||||
if (c == &cache_head)
|
||||
return; // nothing in cache at all
|
||||
if ((byte *) c >= hunk_base + new_low_hunk)
|
||||
return; // there is space to grow the hunk
|
||||
Sys_Error ("FIXME: Cache_FreeLow: not enough memory");
|
||||
Cache_Move (c); // reclaim the space
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_FreeHigh
|
||||
|
||||
Throw things out until the hunk can be expanded to the given point
|
||||
*/
|
||||
static void
|
||||
Cache_FreeHigh (int new_high_hunk)
|
||||
{
|
||||
cache_system_t *c, *prev;
|
||||
|
||||
prev = NULL;
|
||||
while (1) {
|
||||
c = cache_head.prev;
|
||||
if (c == &cache_head)
|
||||
return; // nothing in cache at all
|
||||
if ((byte *) c + c->size <= hunk_base + hunk_size - new_high_hunk)
|
||||
return; // there is space to grow the hunk
|
||||
if (c == prev)
|
||||
Cache_Free (c->user); // didn't move out of the way
|
||||
else {
|
||||
Cache_Move (c); // try to move it
|
||||
prev = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
Cache_UnlinkLRU (cache_system_t * cs)
|
||||
{
|
||||
if (!cs->lru_next || !cs->lru_prev)
|
||||
Sys_Error ("Cache_UnlinkLRU: NULL link");
|
||||
Sys_Error ("Cache_UnlinkLRU: NULL link: %s %p %p",
|
||||
cs->name, cs->lru_next, cs->lru_prev);
|
||||
|
||||
cs->lru_next->lru_prev = cs->lru_prev;
|
||||
cs->lru_prev->lru_next = cs->lru_next;
|
||||
|
@ -648,7 +622,8 @@ static inline void
|
|||
Cache_MakeLRU (cache_system_t * cs)
|
||||
{
|
||||
if (cs->lru_next || cs->lru_prev)
|
||||
Sys_Error ("Cache_MakeLRU: active link");
|
||||
Sys_Error ("Cache_MakeLRU: active link: %s %p %p",
|
||||
cs->name, cs->lru_next, cs->lru_prev);
|
||||
|
||||
cache_head.lru_next->lru_prev = cs;
|
||||
cs->lru_next = cache_head.lru_next;
|
||||
|
@ -656,12 +631,27 @@ Cache_MakeLRU (cache_system_t * cs)
|
|||
cache_head.lru_next = cs;
|
||||
}
|
||||
|
||||
static void
|
||||
check_cache (void)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
for (cs = cache_head.prev; cs != &cache_head; cs = cs->prev)
|
||||
if (cs->prev != &cache_head
|
||||
&& (byte *) cs + cs->size != (byte *) cs->prev)
|
||||
Sys_Error ("inconsistent cache %p %p %d %d", cs, cs->prev,
|
||||
(int)cs->size,
|
||||
(int) ((char *)cs->prev - (char *)cs));
|
||||
}
|
||||
|
||||
static qboolean
|
||||
Cache_FreeLRU (void)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
for (cs = cache_head.lru_prev; cs->readlock; cs = cs->lru_prev)
|
||||
check_cache ();
|
||||
for (cs = cache_head.lru_prev;
|
||||
cs != &cache_head && cs->readlock; cs = cs->lru_prev)
|
||||
;
|
||||
if (cs == &cache_head)
|
||||
return 0;
|
||||
|
@ -669,6 +659,16 @@ Cache_FreeLRU (void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
link_cache_system (cache_system_t *new, cache_system_t *cs)
|
||||
{
|
||||
new->next = cs;
|
||||
new->prev = cs->prev;
|
||||
cs->prev->next = new;
|
||||
cs->prev = new;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_TryAlloc
|
||||
|
||||
|
@ -676,195 +676,58 @@ Cache_FreeLRU (void)
|
|||
Size should already include the header and padding
|
||||
*/
|
||||
static cache_system_t *
|
||||
Cache_TryAlloc (int size, qboolean nobottom)
|
||||
Cache_TryAlloc (size_t size, qboolean nobottom)
|
||||
{
|
||||
cache_system_t *cs, *new;
|
||||
|
||||
// is the cache completely empty?
|
||||
|
||||
if (!nobottom && cache_head.prev == &cache_head) {
|
||||
if (hunk_size - hunk_high_used - hunk_low_used < size) {
|
||||
Sys_Printf ("Cache_TryAlloc: %i is greater then free hunk", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = (cache_system_t *) (hunk_base + hunk_low_used);
|
||||
memset (new, 0, sizeof (*new));
|
||||
new = (cache_system_t *) Hunk_HighAlloc (size);
|
||||
if (!new)
|
||||
return 0;
|
||||
memset (new, 0, size);
|
||||
new->size = size;
|
||||
|
||||
cache_head.prev = cache_head.next = new;
|
||||
new->prev = new->next = &cache_head;
|
||||
|
||||
Cache_MakeLRU (new);
|
||||
return new;
|
||||
}
|
||||
|
||||
// search from the bottom up for space
|
||||
|
||||
new = (cache_system_t *) (hunk_base + hunk_low_used);
|
||||
cs = cache_head.next;
|
||||
|
||||
do {
|
||||
if (!nobottom || cs != cache_head.next) {
|
||||
if ((byte *) cs - (byte *) new >= size) { // found space
|
||||
memset (new, 0, sizeof (*new));
|
||||
// search for space in existing cache
|
||||
for (cs = cache_head.next; cs != &cache_head; cs = cs->next) {
|
||||
if (cs->user)
|
||||
continue; // block isn't free
|
||||
if (cs->size >= size) {
|
||||
// found a big enough free block. If possible, carve it up for
|
||||
// later reuse, using the upper portion of the block for the
|
||||
// newly allocated block.
|
||||
new = cs;
|
||||
if (size - cs->size >= sizeof (cache_system_t)) {
|
||||
new = (cache_system_t *) ((char *) cs + cs->size - size);
|
||||
memset (new, 0, size);
|
||||
new->size = size;
|
||||
|
||||
new->next = cs;
|
||||
new->prev = cs->prev;
|
||||
cs->prev->next = new;
|
||||
cs->prev = new;
|
||||
|
||||
Cache_MakeLRU (new);
|
||||
|
||||
return new;
|
||||
cs->size -= size;
|
||||
link_cache_system (new, cs);
|
||||
}
|
||||
Cache_MakeLRU (new);
|
||||
return new;
|
||||
}
|
||||
// continue looking
|
||||
new = (cache_system_t *) ((byte *) cs + cs->size);
|
||||
cs = cs->next;
|
||||
}
|
||||
|
||||
} while (cs != &cache_head);
|
||||
if (nobottom)
|
||||
return 0;
|
||||
|
||||
// try to allocate one at the very end
|
||||
if (hunk_base + hunk_size - hunk_high_used - (byte *) new >= size) {
|
||||
memset (new, 0, sizeof (*new));
|
||||
// didn't find a free block, so make a new one.
|
||||
new = Hunk_HighAlloc (size);
|
||||
if (new) {
|
||||
memset (new, 0, size);
|
||||
new->size = size;
|
||||
|
||||
new->next = &cache_head;
|
||||
new->prev = cache_head.prev;
|
||||
cache_head.prev->next = new;
|
||||
cache_head.prev = new;
|
||||
|
||||
link_cache_system (new, &cache_head);
|
||||
Cache_MakeLRU (new);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
return NULL; // couldn't allocate
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_Flush
|
||||
|
||||
Throw everything out, so new data will be demand cached
|
||||
*/
|
||||
void
|
||||
Cache_Flush (void)
|
||||
{
|
||||
while (cache_head.next != &cache_head) {
|
||||
if (!cache_head.next->user->data)
|
||||
Sys_Error ("Cache_Flush: user/system out of sync for "
|
||||
"'%s' with %d size",
|
||||
cache_head.next->name, cache_head.next->size);
|
||||
Cache_Free (cache_head.next->user); // reclaim the space
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Cache_Print (void)
|
||||
{
|
||||
cache_system_t *cd;
|
||||
|
||||
for (cd = cache_head.next; cd != &cache_head; cd = cd->next) {
|
||||
Sys_Printf ("%8i : %s\n", cd->size, cd->name);
|
||||
}
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
Cache_Report (void)
|
||||
{
|
||||
Sys_DPrintf ("%4.1f megabyte data cache\n",
|
||||
(hunk_size - hunk_high_used -
|
||||
hunk_low_used) / (float) (1024 * 1024));
|
||||
}
|
||||
|
||||
static void
|
||||
Cache_Init (void)
|
||||
{
|
||||
cache_head.next = cache_head.prev = &cache_head;
|
||||
cache_head.lru_next = cache_head.lru_prev = &cache_head;
|
||||
|
||||
Cmd_AddCommand ("cache_flush", Cache_Flush, "Clears the current game "
|
||||
"cache");
|
||||
Cmd_AddCommand ("cache_profile", Cache_Profile, "Prints a profile of "
|
||||
"the current cache");
|
||||
Cmd_AddCommand ("cache_print", Cache_Print, "Prints out items in the "
|
||||
"cache");
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_Free
|
||||
|
||||
Frees the memory and removes it from the LRU list
|
||||
*/
|
||||
VISIBLE void
|
||||
Cache_Free (cache_user_t *c)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (!c->data)
|
||||
Sys_Error ("Cache_Free: not allocated");
|
||||
|
||||
cs = ((cache_system_t *) c->data) - 1;
|
||||
|
||||
Sys_DPrintf ("Cache_Free: freeing '%s'\n", cs->name);
|
||||
|
||||
cs->prev->next = cs->next;
|
||||
cs->next->prev = cs->prev;
|
||||
cs->next = cs->prev = NULL;
|
||||
|
||||
c->data = NULL;
|
||||
|
||||
Cache_UnlinkLRU (cs);
|
||||
|
||||
}
|
||||
|
||||
VISIBLE void *
|
||||
Cache_Check (cache_user_t *c)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (!c->data)
|
||||
return NULL;
|
||||
|
||||
cs = ((cache_system_t *) c->data) - 1;
|
||||
|
||||
// move to head of LRU
|
||||
Cache_UnlinkLRU (cs);
|
||||
Cache_MakeLRU (cs);
|
||||
|
||||
return c->data;
|
||||
}
|
||||
|
||||
VISIBLE void *
|
||||
Cache_Alloc (cache_user_t *c, int size, const char *name)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (c->data)
|
||||
Sys_Error ("Cache_Alloc: already allocated");
|
||||
|
||||
if (size <= 0)
|
||||
Sys_Error ("Cache_Alloc: size %i", size);
|
||||
|
||||
size = (size + sizeof (cache_system_t) + 15) & ~15;
|
||||
|
||||
// find memory for it
|
||||
while (1) {
|
||||
cs = Cache_TryAlloc (size, false);
|
||||
if (cs) {
|
||||
strncpy (cs->name, name, sizeof (cs->name) - 1);
|
||||
c->data = (void *) (cs + 1);
|
||||
cs->user = c;
|
||||
break;
|
||||
}
|
||||
// free the least recently used cachedat
|
||||
if (!Cache_FreeLRU())
|
||||
Sys_Error ("Cache_Alloc: out of memory");
|
||||
}
|
||||
|
||||
return Cache_Check (c);
|
||||
return 0; // couldn't allocate
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -900,6 +763,149 @@ Cache_Profile (void)
|
|||
" %d per allocation\n", total, count, total / count);
|
||||
}
|
||||
|
||||
static void
|
||||
Cache_Print (void)
|
||||
{
|
||||
cache_system_t *cd;
|
||||
|
||||
for (cd = cache_head.next; cd != &cache_head; cd = cd->next) {
|
||||
Sys_Printf ("%8d : %s\n", (int) cd->size, cd->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Cache_Init (void)
|
||||
{
|
||||
cache_head.next = cache_head.prev = &cache_head;
|
||||
cache_head.lru_next = cache_head.lru_prev = &cache_head;
|
||||
cache_head.user = (cache_user_t *) 1; // make it look allocated
|
||||
cache_head.readlock = 1; // don't try to free or move it
|
||||
|
||||
Cmd_AddCommand ("cache_flush", Cache_Flush, "Clears the current game "
|
||||
"cache");
|
||||
Cmd_AddCommand ("cache_profile", Cache_Profile, "Prints a profile of "
|
||||
"the current cache");
|
||||
Cmd_AddCommand ("cache_print", Cache_Print, "Prints out items in the "
|
||||
"cache");
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_Flush
|
||||
|
||||
Throw everything out, so new data will be demand cached
|
||||
*/
|
||||
void
|
||||
Cache_Flush (void)
|
||||
{
|
||||
while (cache_head.next != &cache_head) {
|
||||
if (!cache_head.next->user->data)
|
||||
Sys_Error ("Cache_Flush: user/system out of sync for "
|
||||
"'%s' with %d size",
|
||||
cache_head.next->name, (int) cache_head.next->size);
|
||||
Cache_Free (cache_head.next->user); // reclaim the space
|
||||
}
|
||||
}
|
||||
|
||||
VISIBLE void *
|
||||
Cache_Check (cache_user_t *c)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (!c->data)
|
||||
return NULL;
|
||||
|
||||
cs = ((cache_system_t *) c->data) - 1;
|
||||
|
||||
// move to head of LRU
|
||||
Cache_UnlinkLRU (cs);
|
||||
Cache_MakeLRU (cs);
|
||||
|
||||
return c->data;
|
||||
}
|
||||
|
||||
/*
|
||||
Cache_Free
|
||||
|
||||
Frees the memory and removes it from the LRU list
|
||||
*/
|
||||
VISIBLE void
|
||||
Cache_Free (cache_user_t *c)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (!c->data)
|
||||
Sys_Error ("Cache_Free: not allocated");
|
||||
|
||||
cs = ((cache_system_t *) c->data) - 1;
|
||||
|
||||
if (cs->readlock)
|
||||
Sys_Error ("Cache_Free: attempt to free locked block");
|
||||
|
||||
Sys_DPrintf ("Cache_Free: freeing '%s' %p\n", cs->name, cs);
|
||||
|
||||
Cache_UnlinkLRU (cs);
|
||||
|
||||
//check_cache ();
|
||||
cs->user = 0;
|
||||
if (!cs->prev->user) {
|
||||
cs->size += cs->prev->size;
|
||||
cs->prev->prev->next = cs;
|
||||
cs->prev = cs->prev->prev;
|
||||
}
|
||||
if (!cs->next->user) {
|
||||
cs = cs->next;
|
||||
cs->size += cs->prev->size;
|
||||
cs->prev->prev->next = cs;
|
||||
cs->prev = cs->prev->prev;
|
||||
}
|
||||
if (cs->next == &cache_head) {
|
||||
cs->next->prev = cs->prev;
|
||||
cs->prev->next = cs->next;
|
||||
Hunk_FreeToHighMark (hunk_high_used - cs->size);
|
||||
}
|
||||
//check_cache ();
|
||||
|
||||
c->data = NULL;
|
||||
}
|
||||
|
||||
VISIBLE void *
|
||||
Cache_Alloc (cache_user_t *c, int size, const char *name)
|
||||
{
|
||||
cache_system_t *cs;
|
||||
|
||||
if (c->data)
|
||||
Sys_Error ("Cache_Alloc: already allocated");
|
||||
|
||||
if (size <= 0)
|
||||
Sys_Error ("Cache_Alloc: size %i", size);
|
||||
|
||||
size = (size + sizeof (cache_system_t) + 15) & ~15;
|
||||
|
||||
// find memory for it
|
||||
while (1) {
|
||||
cs = Cache_TryAlloc (size, false);
|
||||
if (cs) {
|
||||
strncpy (cs->name, name, sizeof (cs->name) - 1);
|
||||
c->data = (void *) (cs + 1);
|
||||
cs->user = c;
|
||||
break;
|
||||
}
|
||||
// free the least recently used cachedat
|
||||
if (!Cache_FreeLRU())
|
||||
Sys_Error ("Cache_Alloc: out of memory");
|
||||
}
|
||||
|
||||
return Cache_Check (c);
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
Cache_Report (void)
|
||||
{
|
||||
Sys_DPrintf ("%4.1f megabyte data cache\n",
|
||||
(hunk_size - hunk_high_used -
|
||||
hunk_low_used) / (float) (1024 * 1024));
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
Cache_Add (cache_user_t *c, void *object, cache_loader_t loader)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue