summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gc.c65
-rw-r--r--txr.130
2 files changed, 58 insertions, 37 deletions
diff --git a/gc.c b/gc.c
index 50b88be9..fc7ec675 100644
--- a/gc.c
+++ b/gc.c
@@ -757,47 +757,50 @@ NOINLINE static void prepare_finals(void)
static val call_finalizers_impl(val ctx,
int (*should_call)(struct fin_reg *, val))
{
- struct fin_reg *f, **tail;
- struct fin_reg *found = 0, **ftail = &found;
val ret = nil;
- if (!final_list)
- return ret;
+ for (;;) {
+ struct fin_reg *f, **tail;
+ struct fin_reg *found = 0, **ftail = &found;
- for (f = final_list, tail = &final_list; f; ) {
- struct fin_reg *next = f->next;
+ for (f = final_list, tail = &final_list; f; ) {
+ struct fin_reg *next = f->next;
- if (should_call(f, ctx)) {
- *ftail = f;
- ftail = &f->next;
- f->next = 0;
- } else {
- *tail = f;
- tail = &f->next;
+ if (should_call(f, ctx)) {
+ *ftail = f;
+ ftail = &f->next;
+ f->next = 0;
+ } else {
+ *tail = f;
+ tail = &f->next;
+ }
+
+ f = next;
}
- f = next;
- }
+ *tail = 0;
+ final_tail = tail;
- *tail = 0;
- final_tail = tail;
+ if (!found)
+ break;
- while (found) {
- struct fin_reg *next = found->next;
- val obj = found->obj;
- funcall1(found->fun, obj);
+ do {
+ struct fin_reg *next = found->next;
+ val obj = found->obj;
+ funcall1(found->fun, obj);
#if CONFIG_GEN_GC
- if (--obj->t.fincount == 0 && inprogress && obj->t.gen == 0) {
- if (freshobj_idx < FRESHOBJ_VEC_SIZE) {
- freshobj[freshobj_idx++] = obj;
- } else {
- full_gc = 1;
+ if (--obj->t.fincount == 0 && inprogress && obj->t.gen == 0) {
+ if (freshobj_idx < FRESHOBJ_VEC_SIZE) {
+ freshobj[freshobj_idx++] = obj;
+ } else {
+ full_gc = 1;
+ }
}
- }
#endif
- free(found);
- found = next;
- ret = t;
+ free(found);
+ found = next;
+ ret = t;
+ } while (found);
}
return ret;
@@ -990,7 +993,7 @@ val gc_finalize(val obj, val fun, val rev_order_p)
struct fin_reg *f = coerce(struct fin_reg *, chk_malloc(sizeof *f));
f->obj = obj;
f->fun = fun;
- f->reachable = 0;
+ f->reachable = 1;
#if CONFIG_GEN_GC
if (++obj->t.fincount == 0) {
diff --git a/txr.1 b/txr.1
index 771d8863..3ce278ac 100644
--- a/txr.1
+++ b/txr.1
@@ -66814,9 +66814,17 @@ A finalizer is itself permitted to call
.code finalize
to register the original
.code object
-or any other object for finalization. Such registrations made during
-finalization execution are not eligible for the current phase of finalization
-processing; they will be processed in a later garbage collection pass.
+or any other object for finalization. Finalization processing can be
+understood as taking place in one or more rounds. At the start of each round,
+finalizers are identified that are to be called, arranged in order, and removed
+from the registration list. If this identification stage produces no
+finalizers, then finalization ends. Otherwise, those finalizers are processed,
+and then another round is initiated, to look for finalizers that may have been
+registered during the previous round.
+
+Note: it is possible for the application to create an infinite finalization
+loop, if one or more objects have finalizers that register new finalizers,
+which register new finalizers and so on.
.coNP Function @ call-finalizers
.synb
@@ -66832,12 +66840,22 @@ If any finalizers are called, it returns
otherwise
.codn nil .
+Finalization performed by
+.code call-finalizers
+works in the manner described under the specification of he
+.code finalize
+function.
+
It is permissible for a finalizer function itself to call
.codn call-finalizers .
-Such a call can happen in two possible contexts: during actual
-reclamation driven by garbage collection, or under the scope of a
+Such a call can happen in two possible contexts: finalization
+initiated by by garbage collection, or under the scope of a
.code call-finalizers
-invocation from application code.
+invocation from application code. Doing so is safe, since the finalization
+logic may be re-entered recursively. When finalizers are being called during a
+round of processing, those finalizers have already been removed from the
+registration list, and will not be redundantly invoked by a recursive
+invocation of finalization.
Under the scope of garbage-collection-driven reclamation, the
order of finalizer calls may not be what the application logic