[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:
Bill Currie 2022-06-05 01:08:45 +09:00
parent 4e550ac9c7
commit 2bb0f0c104
3 changed files with 56 additions and 14 deletions

View file

@ -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);

View file

@ -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

View file

@ -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)
{