diff --git a/.gitattributes b/.gitattributes index 70afb34c903b57ddae877faaa78fbb4c9e5c0b27..c07832fce6edce995d05ee1d213ec0f78cee8e4e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -145,6 +145,7 @@ testfont binary /lib/modules/MIME.pmod foreign_ident /lib/modules/MIME.pmod/ext_to_media_type.pmod foreign_ident /lib/modules/MIME.pmod/module.pmod foreign_ident +/lib/modules/Object.pmod foreign_ident /lib/modules/Parser.pmod/C.pmod foreign_ident /lib/modules/Parser.pmod/LR.pmod/GrammarParser.pmod foreign_ident /lib/modules/Parser.pmod/LR.pmod/lr.pike foreign_ident diff --git a/lib/modules/Object.pmod b/lib/modules/Object.pmod new file mode 100644 index 0000000000000000000000000000000000000000..4cf4d31799bb3592ac367c40b9d1f70815b31dee --- /dev/null +++ b/lib/modules/Object.pmod @@ -0,0 +1,14 @@ +//! $Id: Object.pmod,v 1.1 2005/02/09 16:35:50 mast Exp $ + +#pike __REAL_VERSION__ +#pragma strict_types + +constant DESTRUCT_EXPLICIT = __builtin.DESTRUCT_EXPLICIT; +constant DESTRUCT_NO_REFS = __builtin.DESTRUCT_NO_REFS; +constant DESTRUCT_GC = __builtin.DESTRUCT_GC; +constant DESTRUCT_CLEANUP = __builtin.DESTRUCT_CLEANUP; +//! Flags passed to @[lfun::destroy]. +//! +//! @note +//! @[Object.DESTRUCT_EXPLICIT] is @expr{0@} and +//! @[Object.DESTRUCT_CLEANUP] is @expr{1@} for compatibility. diff --git a/src/builtin_functions.c b/src/builtin_functions.c index 3dee9142037f529d3bd0081fb53becb8d48b7acc..ccae321d19b090e553e4f5399855d1a59a4cb9fb 100644 --- a/src/builtin_functions.c +++ b/src/builtin_functions.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: builtin_functions.c,v 1.586 2004/12/23 13:44:44 grubba Exp $ +|| $Id: builtin_functions.c,v 1.587 2005/02/09 16:35:50 mast Exp $ */ #include "global.h" @@ -2377,7 +2377,7 @@ PMOD_EXPORT void f_destruct(INT32 args) Pike_error("Destruct permission denied.\n"); #endif debug_malloc_touch(o); - destruct(o); + destruct_object (o, DESTRUCT_EXPLICIT); pop_n_elems(args); destruct_objects_to_destruct(); } @@ -8697,4 +8697,9 @@ void init_builtin_efuns(void) ADD_INT_CONSTANT("__FLOAT_PRECISION_FLOAT__",1,0); #endif #endif + + ADD_INT_CONSTANT ("DESTRUCT_EXPLICIT", DESTRUCT_EXPLICIT, 0); + ADD_INT_CONSTANT ("DESTRUCT_NO_REFS", DESTRUCT_NO_REFS, 0); + ADD_INT_CONSTANT ("DESTRUCT_GC", DESTRUCT_GC, 0); + ADD_INT_CONSTANT ("DESTRUCT_CLEANUP", DESTRUCT_CLEANUP, 0); } diff --git a/src/gc.c b/src/gc.c index ac9052458c18d08f74d6981e4fe0722205e72960..52bdf6a0ab1dcb0a0909c022b567eb61b84bb5c4 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: gc.c,v 1.261 2004/09/30 12:12:10 mast Exp $ +|| $Id: gc.c,v 1.262 2005/02/09 16:43:35 mast Exp $ */ #include "global.h" @@ -3041,39 +3041,46 @@ size_t do_gc(void *ignored, int explicit_call) #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) destroy_count = 0; #endif - while (kill_list) { - struct gc_frame *next = NEXT(kill_list); - struct object *o = (struct object *) kill_list->data; -#ifdef PIKE_DEBUG - if (!(kill_list->frameflags & GC_ON_KILL_LIST)) - gc_fatal(o, 0, "Kill list element hasn't got the proper flag.\n"); - if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) != - (GC_LIVE|GC_LIVE_OBJ)) - gc_fatal(o, 0, "Invalid object on kill list.\n"); - if (o->prog && (o->prog->flags & PROGRAM_USES_PARENT) && - PARENT_INFO(o)->parent && - !PARENT_INFO(o)->parent->prog && - get_marker(PARENT_INFO(o)->parent)->flags & GC_LIVE_OBJ) - gc_fatal(o, 0, "GC destructed parent prematurely.\n"); -#endif - GC_VERBOSE_DO( - fprintf(stderr, "| Killing %p with %d refs", o, o->refs); - if (o->prog) { - INT32 line; - struct pike_string *file = get_program_line (o->prog, &line); - fprintf(stderr, ", prog %s:%d\n", file->str, line); - free_string(file); - } - else fputs(", is destructed\n", stderr); - ); - destruct(o); - free_object(o); - gc_free_extra_ref(o); + { + enum object_destruct_reason reason = +#ifdef DO_PIKE_CLEANUP + gc_destruct_everything ? DESTRUCT_CLEANUP : +#endif + DESTRUCT_GC; + while (kill_list) { + struct gc_frame *next = NEXT(kill_list); + struct object *o = (struct object *) kill_list->data; +#ifdef PIKE_DEBUG + if (!(kill_list->frameflags & GC_ON_KILL_LIST)) + gc_fatal(o, 0, "Kill list element hasn't got the proper flag.\n"); + if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) != + (GC_LIVE|GC_LIVE_OBJ)) + gc_fatal(o, 0, "Invalid object on kill list.\n"); + if (o->prog && (o->prog->flags & PROGRAM_USES_PARENT) && + PARENT_INFO(o)->parent && + !PARENT_INFO(o)->parent->prog && + get_marker(PARENT_INFO(o)->parent)->flags & GC_LIVE_OBJ) + gc_fatal(o, 0, "GC destructed parent prematurely.\n"); +#endif + GC_VERBOSE_DO( + fprintf(stderr, "| Killing %p with %d refs", o, o->refs); + if (o->prog) { + INT32 line; + struct pike_string *file = get_program_line (o->prog, &line); + fprintf(stderr, ", prog %s:%d\n", file->str, line); + free_string(file); + } + else fputs(", is destructed\n", stderr); + ); + destruct_object (o, reason); + free_object(o); + gc_free_extra_ref(o); #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) - destroy_count++; + destroy_count++; #endif - debug_really_free_gc_frame(kill_list); - kill_list = next; + debug_really_free_gc_frame(kill_list); + kill_list = next; + } } GC_VERBOSE_DO(fprintf(stderr, "| kill: %u objects killed, %d things really freed\n", diff --git a/src/object.c b/src/object.c index 9e37da28734b3d187424084a5a7aaea891aa8e0c..14377221a46eec5ef9a53c860f39a1ff51208984 100644 --- a/src/object.c +++ b/src/object.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: object.c,v 1.264 2005/01/20 14:29:25 nilsson Exp $ +|| $Id: object.c,v 1.265 2005/02/09 16:35:50 mast Exp $ */ #include "global.h" @@ -669,7 +669,7 @@ PMOD_EXPORT struct program *get_program_for_object_being_destructed(struct objec return 0; } -static void call_destroy(struct object *o, int foo) +static void call_destroy(struct object *o, enum object_destruct_reason reason) { volatile int e; @@ -731,8 +731,8 @@ static void call_destroy(struct object *o, int foo) } else { - if(foo) push_int(1); - apply_low(o, e, foo?1:0); + push_int (reason); + apply_low(o, e, 1); pop_stack(); UNSETJMP (jmp); } @@ -753,7 +753,7 @@ static void call_destroy(struct object *o, int foo) } -void destruct(struct object *o) +PMOD_EXPORT void destruct_object (struct object *o, enum object_destruct_reason reason) { int e; struct program *p; @@ -782,7 +782,7 @@ void destruct(struct object *o) } #endif add_ref( o ); - call_destroy(o,0); + call_destroy(o, reason); /* destructed in destroy() */ if(!(p=o->prog)) @@ -936,7 +936,7 @@ void low_destruct_objects_to_destruct(void) /* call destroy, keep one ref */ add_ref(o); - destruct(o); + destruct_object (o, DESTRUCT_NO_REFS); free_object(o); } while ((o = next)); } @@ -981,7 +981,7 @@ PMOD_EXPORT void schedule_really_free_object(struct object *o) if(o->prog && (o->prog->flags & PROGRAM_DESTRUCT_IMMEDIATE)) { add_ref(o); - destruct(o); + destruct_object (o, DESTRUCT_NO_REFS); if(sub_ref(o)) return; } @@ -1981,6 +1981,11 @@ size_t gc_free_all_unreferenced_objects(void) { struct object *o,*next; size_t unreferenced = 0; + enum object_destruct_reason reason = +#ifdef DO_PIKE_CLEANUP + gc_destruct_everything ? DESTRUCT_CLEANUP : +#endif + DESTRUCT_GC; for(o=gc_internal_object; o; o=next) { @@ -1993,7 +1998,7 @@ size_t gc_free_all_unreferenced_objects(void) gc_fatal(o,0,"Can't free a live object in gc_free_all_unreferenced_objects().\n"); #endif debug_malloc_touch(o); - destruct(o); + destruct_object (o, reason); gc_free_extra_ref(o); SET_NEXT_AND_FREE(o,free_object); @@ -2418,7 +2423,7 @@ void exit_object(void) master_is_cleaned_up = 1; if (master_object) { call_destroy (master_object, 1); - destruct (master_object); + destruct_object (master_object, DESTRUCT_CLEANUP); free_object(master_object); master_object=0; } diff --git a/src/object.h b/src/object.h index a922f860b7375d4dee61357b624e04204626a5e2..88ea536b00bceb447973086cc7a2577d14dd753e 100644 --- a/src/object.h +++ b/src/object.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: object.h,v 1.89 2004/12/03 14:41:14 grubba Exp $ +|| $Id: object.h,v 1.90 2005/02/09 16:35:50 mast Exp $ */ #ifndef OBJECT_H @@ -66,6 +66,13 @@ void gc_check_zapped (void *a, TYPE_T type, const char *file, int line); #define this_object() (add_ref(Pike_fp->current_object), Pike_fp->current_object) +enum object_destruct_reason { + DESTRUCT_EXPLICIT = 0, + DESTRUCT_CLEANUP = 1, + DESTRUCT_NO_REFS, + DESTRUCT_GC +}; + #include "block_alloc_h.h" /* Prototypes begin here */ BLOCK_ALLOC_FILL_PAGES(object, 2) @@ -87,7 +94,8 @@ PMOD_EXPORT struct object *debug_master(void); struct destroy_called_mark; PTR_HASH_ALLOC(destroy_called_mark,128) PMOD_EXPORT struct program *get_program_for_object_being_destructed(struct object * o); -void destruct(struct object *o); +PMOD_EXPORT void destruct_object (struct object *o, enum object_destruct_reason reason); +#define destruct(o) destruct_object (o, DESTRUCT_EXPLICIT) void low_destruct_objects_to_destruct(void); void destruct_objects_to_destruct_cb(void); PMOD_EXPORT void schedule_really_free_object(struct object *o); diff --git a/src/program.c b/src/program.c index 9dbe322aafb9a6d39c77b71e9a0358a87587d2c0..47eb038e3eaa4084fe9818aa0af9f4f9080455aa 100644 --- a/src/program.c +++ b/src/program.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: program.c,v 1.585 2005/01/20 00:27:17 nilsson Exp $ +|| $Id: program.c,v 1.586 2005/02/09 16:35:50 mast Exp $ */ #include "global.h" @@ -163,7 +163,7 @@ static struct mapping *lfun_types; static const char *const raw_lfun_types[] = { tFuncV(tNone,tVoid,tVoid), /* "__INIT", */ tFuncV(tNone,tZero,tVoid), /* "create", */ - tFuncV(tNone,tVoid,tVoid), /* "destroy", */ + tFuncV(tOr(tVoid,tInt),tVoid,tVoid), /* "destroy", */ tFuncV(tZero,tZero,tMix), /* "`+", */ tFunc(tOr(tVoid,tZero),tMix), /* "`-", */ tFuncV(tNone,tZero,tMix), /* "`&", */ @@ -329,17 +329,33 @@ static const char *const raw_lfun_types[] = { *! @[lfun::__INIT()], @[lfun::destroy()] */ -/*! @decl void lfun::destroy() +/*! @decl void lfun::destroy (void|int reason) *! *! Object destruction callback. *! - *! This function is called by @[predef::destruct()] right before it - *! zeroes all the object variables and destroys the object. + *! This function is called right before the object is destructed. + *! That can happen either through a call to @[predef::destruct()], + *! when there are no more references to the object, or when the + *! garbage collector discovers that it's part of a cyclic data + *! structure that has become garbage. *! - *! @note - *! Note that it's also called on implicit destruct, i.e. when there - *! are no more references to the object, or when the garbage - *! collector decides to destruct it. + *! @param reason + *! A flag that tells why the object is destructed: + *! + *! @int + *! @value Object.DESTRUCT_EXPLICIT + *! Destructed explicitly by @[predef::destruct]. + *! @value Object.DESTRUCT_NO_REFS + *! Destructed due to running out of references. + *! @value Object.DESTRUCT_GC + *! Destructed by the garbage collector. + *! @value Object.DESTRUCT_CLEANUP + *! Destructed as part of the cleanup when the pike program + *! exits. Note that Pike normally doesn't do any cleanup before + *! exit - it must be compiled with the configure option + *! @tt{--with-cleanup-on-exit@} to enable that. So this value + *! normally doesn't occur. + *! @endint *! *! @note *! Regarding destruction order during garbage collection: @@ -409,8 +425,8 @@ static const char *const raw_lfun_types[] = { *! still intact. They are not freed if the @expr{destroy@} function *! adds external references to them. However, all objects with *! @[lfun::destroy] in the cycle are already scheduled for - *! destruction and are thus be destroyed even if external references - *! are added to them. + *! destruction and will therefore be destroyed even if external + *! references are added to them. *! *! @note *! The garbage collector had completely random destruct order in @@ -469,7 +485,7 @@ static const char *const raw_lfun_types[] = { *! Right side addition/concatenation callback. *! *! This is used by @[predef::`+]. It's called with any arguments - *! that precedes this object in the argument list of the call to + *! that precede this object in the argument list of the call to *! @[predef::`+]. The returned value should be a new instance that *! represents the addition/concatenation between the arguments in *! the order they are given and this object.