Skip to content

Commit 1794ea0

Browse files
authored
Merge pull request #49 from ruby/mmtk-fork-ractor
Fix forking with multiple Ractors
2 parents 6cd24b4 + 1a62950 commit 1794ea0

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

gc/mmtk/mmtk.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct objspace {
3232
unsigned long live_ractor_cache_count;
3333

3434
pthread_mutex_t mutex;
35+
rb_atomic_t mutator_blocking_count;
3536
bool world_stopped;
3637
pthread_cond_t cond_world_stopped;
3738
pthread_cond_t cond_world_started;
@@ -131,7 +132,9 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
131132
struct objspace *objspace = rb_gc_get_objspace();
132133

133134
size_t starting_gc_count = objspace->gc_count;
135+
RUBY_ATOMIC_INC(objspace->mutator_blocking_count);
134136
int lock_lev = RB_GC_VM_LOCK();
137+
RUBY_ATOMIC_DEC(objspace->mutator_blocking_count);
135138
int err;
136139
if ((err = pthread_mutex_lock(&objspace->mutex)) != 0) {
137140
rb_bug("ERROR: cannot lock objspace->mutex: %s", strerror(err));
@@ -1049,7 +1052,25 @@ rb_gc_impl_before_fork(void *objspace_ptr)
10491052
{
10501053
struct objspace *objspace = objspace_ptr;
10511054

1055+
retry:
10521056
objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK();
1057+
rb_gc_vm_barrier();
1058+
1059+
/* At this point, we know that all the Ractors are paused because of the
1060+
* rb_gc_vm_barrier above. Since rb_mmtk_block_for_gc is a barrier point,
1061+
* one or more Ractors could be paused there. However, mmtk_before_fork is
1062+
* not compatible with that because it assumes that the MMTk workers are idle,
1063+
* but the workers are not idle because they are busy working on a GC.
1064+
*
1065+
* This essentially implements a trylock. It will optimistically lock but will
1066+
* release the lock if it detects that any other Ractors are waiting in
1067+
* rb_mmtk_block_for_gc.
1068+
*/
1069+
rb_atomic_t mutator_blocking_count = RUBY_ATOMIC_LOAD(objspace->mutator_blocking_count);
1070+
if (mutator_blocking_count != 0) {
1071+
RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev);
1072+
goto retry;
1073+
}
10531074

10541075
mmtk_before_fork();
10551076
}

0 commit comments

Comments
 (0)