mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
[zone] Add support for reference counting to Z_*
And use it for Ruamoko object reference counts. I need reference counts for dealing with block sound buffers since they can be shared by many channels. I figured I take care of Ruamoko's reference count location at the same time. Fixes #27.
This commit is contained in:
parent
4e550ac9c7
commit
2bb0f0c104
3 changed files with 56 additions and 14 deletions
|
@ -109,6 +109,9 @@ void Z_CheckHeap (memzone_t *zone);
|
|||
void Z_SetError (memzone_t *zone, void (*err) (void *data, const char *msg),
|
||||
void *data);
|
||||
void Z_CheckPointer (const memzone_t *zone, const void *ptr, size_t size);
|
||||
int Z_IncRetainCount (memzone_t *zone, void *ptr);
|
||||
int Z_DecRetainCount (memzone_t *zone, void *ptr);
|
||||
int Z_GetRetainCount (memzone_t *zone, void *ptr) __attribute__((pure));
|
||||
|
||||
memhunk_t *Hunk_Init (void *buf, size_t size);
|
||||
void Hunk_Print (memhunk_t *hunk, qboolean all);
|
||||
|
|
|
@ -1783,14 +1783,14 @@ rua_class_pose_as (progs_t *pr, void *data)
|
|||
static inline pr_id_t *
|
||||
class_create_instance (progs_t *pr, pr_class_t *class)
|
||||
{
|
||||
int size = (class->instance_size + 1) * sizeof (pr_type_t);
|
||||
int size = class->instance_size * sizeof (pr_type_t);
|
||||
pr_type_t *mem;
|
||||
pr_id_t *id = 0;
|
||||
|
||||
mem = PR_Zone_TagMalloc (pr, size, class->name);
|
||||
if (mem) {
|
||||
memset (mem, 0, size);
|
||||
id = (pr_id_t *) (mem + 1);
|
||||
id = (pr_id_t *) mem;
|
||||
id->class_pointer = PR_SetPointer (pr, class);
|
||||
}
|
||||
return id;
|
||||
|
@ -1908,7 +1908,7 @@ rua_object_dispose (progs_t *pr, void *data)
|
|||
{
|
||||
pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0);
|
||||
pr_type_t *mem = (pr_type_t *) object;
|
||||
PR_Zone_Free (pr, mem - 1);
|
||||
PR_Zone_Free (pr, mem);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -75,8 +75,10 @@ typedef struct memblock_s {
|
|||
struct memblock_s *next;
|
||||
struct memblock_s *prev;
|
||||
size_t size; // requested size
|
||||
byte pad[64 - 3 * 4 - 4 * sizeof (size_t)];
|
||||
int tag; // a tag of 0 is a free block
|
||||
int id; // should be ZONEID
|
||||
int retain; // reference counter (optional usage)
|
||||
} __attribute__((aligned (64))) memblock_t;
|
||||
|
||||
struct memzone_s {
|
||||
|
@ -104,10 +106,20 @@ z_offset (memzone_t *zone, memblock_t *block)
|
|||
return offset / zone->ele_size + zone->offset;
|
||||
}
|
||||
|
||||
static void
|
||||
z_error (memzone_t *zone, const char *msg)
|
||||
{
|
||||
if (zone->error)
|
||||
zone->error (zone->data, msg);
|
||||
Sys_Error ("%s", msg);
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
Z_ClearZone (memzone_t *zone, size_t size, size_t zone_offset, size_t ele_size)
|
||||
{
|
||||
memblock_t *block;
|
||||
memblock_t *block
|
||||
= __builtin_choose_expr (__builtin_offsetof (memblock_t, retain) == 60,
|
||||
0, (void) 0);
|
||||
|
||||
// set the entire zone to one free block
|
||||
|
||||
|
@ -170,6 +182,13 @@ Z_Free (memzone_t *zone, void *ptr)
|
|||
zone->error (zone->data, "Z_Free: freed a freed pointer");
|
||||
Sys_Error ("Z_Free: freed a freed pointer");
|
||||
}
|
||||
if (block->retain) {
|
||||
const char *msg = nva ("Z_Free: freed a retained pointer: %d",
|
||||
block->retain);
|
||||
if (zone->error)
|
||||
zone->error (zone->data, msg);
|
||||
Sys_Error ("%s", msg);
|
||||
}
|
||||
|
||||
block->tag = 0; // mark as free
|
||||
block->size = 0;
|
||||
|
@ -265,6 +284,7 @@ Z_TagMalloc (memzone_t *zone, size_t size, int tag)
|
|||
base->block_size = size;
|
||||
}
|
||||
|
||||
base->retain = 0; // use is optional, but must be 0 to free
|
||||
base->tag = tag; // no longer a free block
|
||||
base->size = requested_size;
|
||||
|
||||
|
@ -339,9 +359,9 @@ Z_Print (memzone_t *zone)
|
|||
zone->size, zone, zone->used);
|
||||
|
||||
for (block = zone->blocklist.next ; ; block = block->next) {
|
||||
Sys_Printf ("block:%p size:%7i tag:%5x ofs:%x\n",
|
||||
Sys_Printf ("block:%p size:%7i tag:%5x ret: %5d ofs:%x\n",
|
||||
block, z_block_size (block),
|
||||
block->tag, z_offset (zone, block));
|
||||
block->tag, block->retain, z_offset (zone, block));
|
||||
|
||||
if (block->next == &zone->blocklist)
|
||||
break; // all blocks have been hit
|
||||
|
@ -361,14 +381,6 @@ Z_Print (memzone_t *zone)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
z_error (memzone_t *zone, const char *msg)
|
||||
{
|
||||
if (zone->error)
|
||||
zone->error (zone->data, msg);
|
||||
Sys_Error ("%s", msg);
|
||||
}
|
||||
|
||||
void
|
||||
Z_CheckHeap (memzone_t *zone)
|
||||
{
|
||||
|
@ -429,6 +441,33 @@ Z_CheckPointer (const memzone_t *zone, const void *ptr, size_t size)
|
|||
}
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
Z_IncRetainCount (memzone_t *zone, void *ptr)
|
||||
{
|
||||
memblock_t *block = (memblock_t *) ((byte *) ptr - sizeof (memblock_t));
|
||||
if (!++block->retain) {
|
||||
z_error (zone, "inc retain count wrapped to 0");
|
||||
}
|
||||
return block->retain;
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
Z_DecRetainCount (memzone_t *zone, void *ptr)
|
||||
{
|
||||
memblock_t *block = (memblock_t *) ((byte *) ptr - sizeof (memblock_t));
|
||||
if (--block->retain == -1) {
|
||||
z_error (zone, "dec retain count wrapped past 0");
|
||||
}
|
||||
return block->retain;
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
Z_GetRetainCount (memzone_t *zone, void *ptr)
|
||||
{
|
||||
memblock_t *block = (memblock_t *) ((byte *) ptr - sizeof (memblock_t));
|
||||
return block->retain;
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
Z_MemInfo (const memzone_t *zone, size_t *used, size_t *size)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue