[前][次][番号順一覧][スレッド一覧]

ruby-changes:58479

From: Aaron <ko1@a...>
Date: Tue, 29 Oct 2019 06:51:00 +0900 (JST)
Subject: [ruby-changes:58479] 60a7f9f446 (master): Protect finalizer references during execution

https://git.ruby-lang.org/ruby.git/commit/?id=60a7f9f446

From 60a7f9f446604571f8a81499080c57c47baf0e6b Mon Sep 17 00:00:00 2001
From: Aaron Patterson <tenderlove@r...>
Date: Thu, 17 Oct 2019 11:37:32 -0700
Subject: Protect finalizer references during execution

When we run finalizers we have to copy all of the finalizers to a new
data structure because a finalizer could add another finalizer and we
need to keep draining the "real" finalizer table until it's empty.
We don't want Ruby programs to mutate the finalizers that we're
iterating over as well.

Before this commit we would copy the finalizers in to a linked list.
The problem with this approach is that if compaction happens, the linked
list will need to be updated.  But the GC doesn't know about the
existence of the linked list, so it could not update references.  This
commit changes the linked list to be a Ruby array so that when
compaction happens, the arrays will automatically be updated and all
references remain valid.

diff --git a/gc.c b/gc.c
index 6fcdf2a..19551ac 100644
--- a/gc.c
+++ b/gc.c
@@ -3370,12 +3370,7 @@ struct force_finalize_list { https://github.com/ruby/ruby/blob/trunk/gc.c#L3370
 static int
 force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
 {
-    struct force_finalize_list **prev = (struct force_finalize_list **)arg;
-    struct force_finalize_list *curr = ALLOC(struct force_finalize_list);
-    curr->obj = key;
-    curr->table = val;
-    curr->next = *prev;
-    *prev = curr;
+    rb_ary_push((VALUE)arg, rb_ary_new_from_args(2, (VALUE)key, (VALUE)val));
     return ST_CONTINUE;
 }
 
@@ -3402,16 +3397,18 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace) https://github.com/ruby/ruby/blob/trunk/gc.c#L3397
 
     /* force to run finalizer */
     while (finalizer_table->num_entries) {
-	struct force_finalize_list *list = 0;
-	st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
-	while (list) {
-	    struct force_finalize_list *curr = list;
-	    st_data_t obj = (st_data_t)curr->obj;
-	    run_finalizer(objspace, curr->obj, curr->table);
+        long i;
+	VALUE list = rb_ary_new_capa(finalizer_table->num_entries);
+
+	st_foreach(finalizer_table, force_chain_object, (st_data_t)list);
+
+        for (i = 0; i < RARRAY_LEN(list); i++) {
+            VALUE tuple = RARRAY_AREF(list, i);
+            VALUE obj = RARRAY_AREF(tuple, 0);
+            VALUE table = RARRAY_AREF(tuple, 1);
+	    run_finalizer(objspace, obj, table);
 	    st_delete(finalizer_table, &obj, 0);
-	    list = curr->next;
-	    xfree(curr);
-	}
+        }
     }
 
     /* prohibit GC because force T_DATA finalizers can break an object graph consistency */
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]