diff --git a/include/Makefile.am b/include/Makefile.am index 30a7c6ee9..00dcf18ff 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 \ diff --git a/include/QF/object.h b/include/QF/object.h index 992da60fd..f8b753581 100644 --- a/include/QF/object.h +++ b/include/QF/object.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" diff --git a/include/garbage.h b/include/garbage.h new file mode 100644 index 000000000..d5766d2d8 --- /dev/null +++ b/include/garbage.h @@ -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 diff --git a/libs/object/ArrayList.c b/libs/object/ArrayList.c index d10290613..528a9eff5 100644 --- a/libs/object/ArrayList.c +++ b/libs/object/ArrayList.c @@ -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); diff --git a/libs/object/Makefile.am b/libs/object/Makefile.am index d68009ec0..36d508bab 100644 --- a/libs/object/Makefile.am +++ b/libs/object/Makefile.am @@ -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 diff --git a/libs/object/garbage.c b/libs/object/garbage.c new file mode 100644 index 000000000..fa7982da6 --- /dev/null +++ b/libs/object/garbage.c @@ -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 + +#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; +} diff --git a/libs/object/object.c b/libs/object/object.c index 473bf34dc..0cfef3f71 100644 --- a/libs/object/object.c +++ b/libs/object/object.c @@ -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); +} diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index d0c800b68..3ad38f5f0 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -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