Skip to content

Commit febd60f

Browse files
committed
Fix forking in multi-ractor scenario
When there are multiple Ractors, there is a chance that one Ractor triggers GC when another Ractor has just stopped all MMTk GC work threads in order to fork. If this happens, the forking thread will be blocking waiting for the Ractor sched barrier, and the Ractor that triggered GC will be waiting for GC threads to finish GC, which will never happen. We move the invocations of `rb_gc_before_fork()` and `rb_gc_after_fork()` inside the `RB_VM_LOCKING() { ... }` block in `rb_fork_ruby`. By doing this, either the forking Ractor will wait for GC to finish before stopping GC worker threads, or the Ractor that triggers GC cannot stop other threads until the forking ractor respawned GC worker threads. We also hold the VM lock when running finalizers when the VM is about to exits.
1 parent b669f3e commit febd60f

File tree

2 files changed

+20
-17
lines changed

2 files changed

+20
-17
lines changed

mmtk_support.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -937,21 +937,25 @@ rb_mmtk_call_obj_free_for_each_on_exit(VALUE *objects, size_t len)
937937
void
938938
rb_mmtk_call_obj_free_on_exit(void)
939939
{
940-
struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
941-
rb_mmtk_call_obj_free_for_each_on_exit((VALUE*)registered_candidates.ptr, registered_candidates.len);
942-
mmtk_free_raw_vec_of_obj_ref(registered_candidates);
943-
944-
rb_vm_t *vm = GET_VM();
945-
rb_ractor_t *ractor;
946-
947-
ccan_list_for_each(&vm->ractor.set, ractor, vmlr_node) {
948-
// ractor.set only contains blocking or running ractors
949-
GC_ASSERT(rb_ractor_status_p(ractor, ractor_blocking) ||
950-
rb_ractor_status_p(ractor, ractor_running));
951-
struct rb_mmtk_mutator_local *local = rb_mmtk_ractor_get_mutator_local(ractor);
952-
struct rb_mmtk_values_buffer *buffer = &local->obj_free_candidates;
953-
rb_mmtk_call_obj_free_for_each_on_exit(buffer->objects, buffer->len);
940+
unsigned int lev = RB_GC_VM_LOCK();
941+
{
942+
struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
943+
rb_mmtk_call_obj_free_for_each_on_exit((VALUE*)registered_candidates.ptr, registered_candidates.len);
944+
mmtk_free_raw_vec_of_obj_ref(registered_candidates);
945+
946+
rb_vm_t *vm = GET_VM();
947+
rb_ractor_t *ractor;
948+
949+
ccan_list_for_each(&vm->ractor.set, ractor, vmlr_node) {
950+
// ractor.set only contains blocking or running ractors
951+
GC_ASSERT(rb_ractor_status_p(ractor, ractor_blocking) ||
952+
rb_ractor_status_p(ractor, ractor_running));
953+
struct rb_mmtk_mutator_local *local = rb_mmtk_ractor_get_mutator_local(ractor);
954+
struct rb_mmtk_values_buffer *buffer = &local->obj_free_candidates;
955+
rb_mmtk_call_obj_free_for_each_on_exit(buffer->objects, buffer->len);
956+
}
954957
}
958+
RB_GC_VM_UNLOCK(lev);
955959
}
956960

957961
bool

process.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,15 +1575,12 @@ after_exec(void)
15751575
static void
15761576
before_fork_ruby(void)
15771577
{
1578-
rb_gc_before_fork();
15791578
before_exec();
15801579
}
15811580

15821581
static void
15831582
after_fork_ruby(rb_pid_t pid)
15841583
{
1585-
rb_gc_after_fork(pid);
1586-
15871584
if (pid == 0) {
15881585
// child
15891586
clear_pid_cache();
@@ -4138,8 +4135,10 @@ rb_fork_ruby(int *status)
41384135
disable_child_handler_before_fork(&old);
41394136

41404137
RB_VM_LOCKING() {
4138+
rb_gc_before_fork();
41414139
child.pid = pid = rb_fork();
41424140
child.error = err = errno;
4141+
rb_gc_after_fork(pid);
41434142
}
41444143

41454144
disable_child_handler_fork_parent(&old); /* yes, bad name */

0 commit comments

Comments
 (0)