Fix a bug with ArrayList_Deinit_f (tried too hard to be clever), and add

an incremental, reference counting garbage collector for QFobjects.  A
different kind of collector will eventually be needed to run once in a
while to sweep up cyclic structures.
This commit is contained in:
Brian Koropoff 2003-12-07 22:45:32 +00:00
parent 7598ab35fb
commit e498b196fe
8 changed files with 162 additions and 22 deletions

View file

@ -4,7 +4,7 @@ SUBDIRS = QF
EXTRA_DIST = asm_i386.h alsa_funcs_list.h adivtab.h anorm_dots.h anorms.h \
asm_draw.h block16.h block8.h buildnum.h compat.h context_sdl.h \
context_x11.h d_iface.h d_ifacea.h d_local.h dga_check.h exp.h fbset.h \
getopt.h gib_buffer.h gib_builtin.h gib_classes.h gib_execute.h gib_function.h \
garbage.h getopt.h gib_buffer.h gib_builtin.h gib_classes.h gib_execute.h gib_function.h \
gib_handle.h gib_object.h gib_parse.h gib_process.h gib_regex.h gib_semantics.h \
gib_thread.h gib_tree.h gib_vars.h gl_warp_sin.h in_win.h logos.h menu.h \
net_dgrm.h net_loop.h net_udp.h net_vcr.h net_wins.h netchan.h netmain.h \

View file

@ -40,14 +40,14 @@
#ifdef __GNUC__
#define superInit(cl, obj, args...) (cl##_class->parent->init ((obj) , ## args))
#define new(cl, args...) ((void *) (cl##_class->abstract ? NULL : retain(cl##_class->init (Object_Create(cl##_class) , ## args))))
#define newFloat(cl, args...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class) , ## args)))
#define new(cl, args...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class, false), ## args)))
#define newFloat(cl, args...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class, true) , ## args)))
#define methodCall(obj, m, args...) ((obj)->m(obj , ## args))
#define methodDecl(type, name, args...) (* name) (struct type##_s *self , ## args)
#else
#define superInit(cl, obj, ...) (cl##_class->parent->init ((obj), ##__VA_ARGS__))
#define new(cl, ...) ((void *) (cl##_class->abstract ? NULL : retain(cl##_class->init (Object_Create(cl##_class), ##__VA_ARGS__))))
#define newFloat(cl, ...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class), ##__VA_ARGS__)))
#define new(cl, ...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class, false) , ##__VA_ARGS__)))
#define newFloat(cl, ...) ((void *) (cl##_class->abstract ? NULL : cl##_class->init (Object_Create(cl##_class, true) , ##__VA_ARGS__)))
#define methodCall(obj, m, ...) ((obj)->m(obj, ##__VA_ARGS__))
#define methodDecl(type, name, ...) (* name) (struct type##_s *self, ##__VA_ARGS__)
#endif
@ -70,9 +70,12 @@ typedef void (*ReplyHandler_t) (struct Object_s *retValue);
typedef struct Object_s {
struct Class_s *cl;
int refs;
qboolean junked;
struct Object_s *next;
struct String_s * methodDecl(Object, toString);
void methodDecl(Object, message, const char *name, struct List_s *args, struct Object_s *sender, ReplyHandler_t *reply);
void *data;
} Object;
extern struct Class_s * Object_class;
#define OBJECT(o) ((Object *)(o))
@ -91,12 +94,13 @@ classDecl (Class, Object,
);
#define CLASS(o) ((Class *)(o))
Object *Object_Create (Class *cl);
Object *Object_Create (Class *cl, qboolean floating);
void Object_Delete (Object *obj);
Object *Object_Retain (Object *obj);
Object *Object_Release (Object *obj);
qboolean Object_InstanceOf (Object *obj, Class *cl);
void Object_Init (void);
void Object_Garbage_Collect (void);
#include "QF/classes/List.h"
#include "QF/classes/String.h"

39
include/garbage.h Normal file
View file

@ -0,0 +1,39 @@
/*
garbage.h
Object system garbage collector
Copyright (C) 2003 Brian Koropoff
Author: Brian Koropoff
Date: November 28, 2003
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifndef __garbage_h
#define __garbage_h
void Garbage_Junk_Object (Object *o);
unsigned int Garbage_Amount (void);
void Garbage_Collect (unsigned int amount);
#endif

View file

@ -214,7 +214,7 @@ static void
ArrayList_Deinit_f (Object *self)
{
unsigned int i;
for (i = COLLECTION(self)->count; --i > 0;)
for (i = 0; i < COLLECTION(self)->count; i++)
if (ARRAYLIST(self)->elements[i])
release(ARRAYLIST(self)->elements[i]);
free(ARRAYLIST(self)->elements);

View file

@ -7,4 +7,4 @@ lib_LTLIBRARIES= libQFobject.la
libQFobject_la_LDFLAGS= -version-info 1:0:0
libQFobject_la_SOURCES= \
ArrayList.c Collection.c Double.c Integer.c Iterator.c \
List.c Number.c String.c object.c
List.c Number.c String.c garbage.c object.c

89
libs/object/garbage.c Normal file
View file

@ -0,0 +1,89 @@
/*
garbage.c
Object system garbage collector.
Copyright (C) 2003 Brian Koropoff
Author: Brian Koropoff
Date: November 28, 2003
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#include <stdlib.h>
#include "QF/sys.h"
#include "QF/object.h"
#include "garbage.h"
unsigned int junked = 0;
Object *junk = NULL;
void
Garbage_Junk_Object (Object *o)
{
Sys_DPrintf ("GC: %s@%p ready for collection.\n", o->cl->name, o);
if (!o->junked && !o->refs) {
o->next = junk;
junk = o;
o->junked = true;
junked++;
}
}
unsigned int
Garbage_Amount (void)
{
return junked;
}
void
Garbage_Collect (unsigned int amount)
{
Object *o;
if (!amount)
return;
Sys_DPrintf ("GC: Collecting %u objects...\n", amount);
for (o = junk; o && amount; o = junk) {
junk = o->next;
if (!o->refs) {
Sys_DPrintf("GC: Collecting %s@%p...\n", o->cl->name, o);
Object_Delete (o);
amount--;
} else {
Sys_DPrintf("GC: %s@%p gained references, not collecting...\n", o->cl->name, o);
o->junked = false;
}
junked--;
}
junk = o;
}

View file

@ -52,7 +52,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/sys.h"
#include "QF/object.h"
#include "QF/va.h"
#include "QF/object.h"
#include "garbage.h"
#include "QF/classes/ArrayList.h"
#include "QF/classes/Integer.h"
@ -67,7 +67,6 @@ Object_ToString_f (Object *self)
static void
Object_Init_f (Object *self)
{
self->refs = -1; // Floating reference
self->toString = Object_ToString_f;
Sys_DPrintf("%s@%p initing...\n", self->cl->name, self);
}
@ -105,10 +104,16 @@ Class_Deinit_f (Object *self) {
Object *
Object_Create (Class *cl)
Object_Create (Class *cl, qboolean floating)
{
Object *new = malloc (cl->size);
new->cl = cl;
new->junked = false;
if (floating) {
new->refs = 0;
Garbage_Junk_Object (new);
} else
new->refs = 1;
return new;
}
@ -123,23 +128,15 @@ Object_Delete (Object *obj)
Object *
Object_Retain (Object *obj)
{
if (obj->refs == -1) {
obj->refs = 1;
} else {
obj->refs++;
}
obj->refs++;
return obj;
}
Object *
Object_Release (Object *obj)
{
if (obj->refs == -1)
Sys_Error ("%s@%p with floating reference released.", obj->cl->name, obj);
if (--obj->refs < 1) {
Object_Delete (obj);
return NULL;
}
if (obj->refs && --obj->refs == 0)
Garbage_Junk_Object (obj);
return obj;
}
@ -214,3 +211,11 @@ Object_Init (void)
/* Run test */
Object_Test();
}
void
Object_Garbage_Collect (void)
{
unsigned int amount;
if ((amount = Garbage_Amount()))
Garbage_Collect (amount / 2 + 1);
}

View file

@ -1895,6 +1895,8 @@ SV_CheckVars (void)
SV_GarbageCollect
Run string GC on progs every pr_gc_interval frames
snax: run QFobject GC as well
*/
static void
SV_GarbageCollect (void)
@ -1905,6 +1907,7 @@ SV_GarbageCollect (void)
if (pr_gc_count >= pr_gc_interval->int_val) {
pr_gc_count = 0;
PR_GarbageCollect (&sv_pr_state);
Object_Garbage_Collect ();
}
} else {
// Make sure the count gets reset if the gc is disabled. I