[ruby-dev:24359] Re: finalizer

From: nobu@...
Date: 2004-09-27 04:41:36 UTC
List: ruby-dev #24359
なかだです。

At Mon, 27 Sep 2004 12:59:00 +0900,
Tanaka Akira wrote in [ruby-dev:24354]:
> > これってどうなるのが正しいんでしょうね。
> 
> これまでの経験の結果、finalizer の実行を gc から直接行なうのが良くない、
> という考えに至りました。
> 
> finalizer の実行は、rb_eval などのユーザのコードが動いてもおかしくない
> タイミングまで遅延する挙動をデフォルトにするほうがよいのではないでしょ
> うか。
> 
> そうすれば、メモリ確保のタイミングでユーザのコードが動いて配列の長さや
> ら何やらが変わってしまうことを考慮せずに済みます。

なるほど。全ノードごとにコストが増えるのは避けたいので、stack
checkと同じタイミングに入れてみました。


Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.703
diff -U2 -p -d -r1.703 eval.c
--- eval.c	24 Sep 2004 16:58:50 -0000	1.703
+++ eval.c	27 Sep 2004 04:32:29 -0000
@@ -5467,4 +5467,5 @@ rb_call0(klass, recv, id, oid, argc, arg
 	CHECK_INTS;		/* better than nothing */
 	stack_check();
+	rb_gc_finalize_deferred();
     }
     PUSH_ITER(itr);
Index: gc.c
===================================================================
RCS file: /cvs/ruby/src/ruby/gc.c,v
retrieving revision 1.185
diff -U2 -p -d -r1.185 gc.c
--- gc.c	24 Sep 2004 05:53:42 -0000	1.185
+++ gc.c	27 Sep 2004 04:30:24 -0000
@@ -994,4 +994,39 @@ static void obj_free _((VALUE));
 
 static void
+finalize_list(p)
+    RVALUE *p;
+{
+    while (p) {
+	RVALUE *tmp = p->as.free.next;
+	run_final((VALUE)p);
+	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
+	    p->as.free.flags = 0;
+	    p->as.free.next = freelist;
+	    freelist = p;
+	}
+	p = tmp;
+    }
+}
+
+static void
+free_unused_heaps()
+{
+    int i, j;
+
+    for (i = j = 1; j < heaps_used; i++) {
+	if (heaps[i].limit == 0) {
+	    free(heaps[i].slot);
+	    heaps_used--;
+	}
+	else {
+	    if (i != j) {
+		heaps[j] = heaps[i];
+	    }
+	    j++;
+	}
+    }
+}
+
+static void
 gc_sweep()
 {
@@ -1065,33 +1100,8 @@ gc_sweep()
     /* clear finalization list */
     if (final_list) {
-	RVALUE *tmp;
-
-	if (rb_prohibit_interrupt) {
-	    deferred_final_list = final_list;
-	    return;
-	}
-
-	for (p = final_list; p; p = tmp) {
-	    tmp = p->as.free.next;
-	    run_final((VALUE)p);
-	    if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
-		p->as.free.flags = 0;
-		p->as.free.next = freelist;
-		freelist = p;
-	    }
-	}
-    }
-    for (i = j = 1; j < heaps_used; i++) {
-	if (heaps[i].limit == 0) {
-	    free(heaps[i].slot);
-	    heaps_used--;
-	}
-	else {
-	    if (i != j) {
-		heaps[j] = heaps[i];
-	    }
-	    j++;
-	}
+	deferred_final_list = final_list;
+	return;
     }
+    free_unused_heaps();
 }
 
@@ -1775,4 +1785,16 @@ run_final(obj)
 
 void
+rb_gc_finalize_deferred()
+{
+    RVALUE *p = deferred_final_list;
+
+    deferred_final_list = 0;
+    if (p) {
+	finalize_list(p);
+	free_unused_heaps();
+    }
+}
+
+void
 rb_gc_call_finalizer_at_exit()
 {
@@ -1782,12 +1804,5 @@ rb_gc_call_finalizer_at_exit()
     /* run finalizers */
     if (need_call_final) {
-	if (deferred_final_list) {
-	    p = deferred_final_list;
-	    while (p) {
-		RVALUE *tmp = p;
-		p = p->as.free.next;
-		run_final((VALUE)tmp);
-	    }
-	}
+	finalize_list(deferred_final_list);
 	for (i = 0; i < heaps_used; i++) {
 	    p = heaps[i].slot; pend = p + heaps[i].limit;


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread