mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
6147fa82a9
commit
60a7f9f446
1 changed files with 12 additions and 15 deletions
27
gc.c
27
gc.c
|
@ -3370,12 +3370,7 @@ struct force_finalize_list {
|
|||
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)
|
|||
|
||||
/* 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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue