mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
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:
parent
7598ab35fb
commit
e498b196fe
8 changed files with 162 additions and 22 deletions
|
@ -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 \
|
||||
|
|
|
@ -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
39
include/garbage.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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
89
libs/object/garbage.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue