Skip to content

Commit

Permalink
release sched_lock before VM lock
Browse files Browse the repository at this point in the history
to avoid deadlock

```ruby
r = Ractor.new do
  obj = Thread.new{}
  Ractor.yield obj
rescue => e
  e.message
end
p r.take
```

```
(lldb) bt
* thread #1, name = 'miniruby', stop reason = signal SIGSTOP
  * frame #0: 0x0000ffff44881410 libpthread.so.0`__lll_lock_wait + 88
    frame #1: 0x0000ffff4487a078 libpthread.so.0`__pthread_mutex_lock + 232
    frame ruby#2: 0x0000aaab617c0980 miniruby`rb_native_mutex_lock(lock=<unavailable>) at thread_pthread.c:109:14
    frame ruby#3: 0x0000aaab617c1d58 miniruby`ubf_event_waiting [inlined] thread_sched_lock_(th=0x0000aaab9df82980, file=<unavailable>, line=46, sched=0x0000aaab9dec79b8) at thread_pthread.c:351:5
    frame ruby#4: 0x0000aaab617c1d50 miniruby`ubf_event_waiting(ptr=0x0000aaab9df82980) at thread_pthread_mn.c:46:5
    frame ruby#5: 0x0000aaab617c6020 miniruby`rb_threadptr_interrupt [inlined] rb_threadptr_interrupt_common(trap=0, th=0x0000aaab9df82980) at thread.c:352:25
    frame ruby#6: 0x0000aaab617c5fec miniruby`rb_threadptr_interrupt(th=0x0000aaab9df82980) at thread.c:365:5
    frame ruby#7: 0x0000aaab617379b0 miniruby`rb_ractor_terminate_all at ractor.c:2364:13
    frame ruby#8: 0x0000aaab6173797c miniruby`rb_ractor_terminate_all at ractor.c:2383:17
    frame ruby#9: 0x0000aaab61737958 miniruby`rb_ractor_terminate_all [inlined] ractor_terminal_interrupt_all(vm=0x0000aaab9dea3320) at ractor.c:2375:1
    frame ruby#10: 0x0000aaab61737950 miniruby`rb_ractor_terminate_all at ractor.c:2424:13
    frame ruby#11: 0x0000aaab6164f108 miniruby`rb_ec_cleanup(ec=0x0000aaab9dea5900, ex=RUBY_TAG_NONE) at eval.c:239:9
    frame ruby#12: 0x0000aaab6164fa3c miniruby`ruby_run_node(n=0x0000ffff417ed178) at eval.c:328:12
    frame ruby#13: 0x0000aaab615a5ab0 miniruby`main at main.c:39:12
    frame ruby#14: 0x0000aaab615a5a98 miniruby`main(argc=<unavailable>, argv=<unavailable>) at main.c:58:12
    frame ruby#15: 0x0000ffff44714b2c libc.so.6`__libc_start_main + 228
    frame ruby#16: 0x0000aaab615a5b0c miniruby`_start + 52
(lldb) thread select 3
* thread ruby#3, name = 'bootstraptest.*', stop reason = signal SIGSTOP
    frame #0: 0x0000ffff448813ec libpthread.so.0`__lll_lock_wait + 52
libpthread.so.0`__lll_lock_wait:
->  0xffff448813ec <+52>: svc    #0
    0xffff448813f0 <+56>: eor    w20, w20, #0x80
    0xffff448813f4 <+60>: sxtw   x20, w20
    0xffff448813f8 <+64>: b      0xffff44881414            ; <+92>
(lldb) bt
* thread ruby#3, name = 'bootstraptest.*', stop reason = signal SIGSTOP
  * frame #0: 0x0000ffff448813ec libpthread.so.0`__lll_lock_wait + 52
    frame #1: 0x0000ffff4487a078 libpthread.so.0`__pthread_mutex_lock + 232
    frame ruby#2: 0x0000aaab617c0980 miniruby`rb_native_mutex_lock(lock=<unavailable>) at thread_pthread.c:109:14
    frame ruby#3: 0x0000aaab61823d68 miniruby`rb_vm_lock_enter_body [inlined] vm_lock_enter(no_barrier=false, lev=0x0000ffff215bfbe4, locked=false, vm=0x0000aaab9dea3320, cr=0x0000aaab9dec7890) at vm_sync.c:57:9
    frame ruby#4: 0x0000aaab61823d60 miniruby`rb_vm_lock_enter_body(lev=0x0000ffff215bfbe4) at vm_sync.c:119:9
    frame ruby#5: 0x0000aaab617c1b30 miniruby`thread_sched_setup_running_threads [inlined] rb_vm_lock_enter(file=<unavailable>, line=597, lev=0x0000ffff215bfbe4) at vm_sync.h:75:9
    frame ruby#6: 0x0000aaab617c1b14 miniruby`thread_sched_setup_running_threads(vm=0x0000aaab9dea3320, add_th=0x0000aaab9df82980, del_th=<unavailable>, add_timeslice_th=0x0000000000000000, cr=<unavailable>, sched=<unavailable>, sched=<unavailable>) at thread_pthread.c:597:9
    frame ruby#7: 0x0000aaab617c29b4 miniruby`thread_sched_wait_running_turn at thread_pthread.c:614:5
    frame ruby#8: 0x0000aaab617c298c miniruby`thread_sched_wait_running_turn(sched=0x0000aaab9dec79b8, th=0x0000aaab9df82980, can_direct_transfer=true) at thread_pthread.c:868:9
    frame ruby#9: 0x0000aaab617c6f0c miniruby`thread_sched_wait_events(sched=0x0000aaab9dec79b8, th=0x0000aaab9df82980, fd=<unavailable>, events=<unavailable>, rel=<unavailable>) at thread_pthread_mn.c:90:17
    frame ruby#10: 0x0000aaab617c7354 miniruby`rb_thread_terminate_all at thread_pthread.c:3248:13
    frame ruby#11: 0x0000aaab617c733c miniruby`rb_thread_terminate_all(th=0x0000aaab9df82980) at thread.c:466:13
    frame ruby#12: 0x0000aaab617c7a64 miniruby`thread_start_func_2(th=0x0000aaab9df82980, stack_start=<unavailable>) at thread.c:713:9
    frame ruby#13: 0x0000aaab617c7d1c miniruby`co_start [inlined] call_thread_start_func_2(th=0x0000aaab9df82980) at thread_pthread.c:2165:5
    frame ruby#14: 0x0000aaab617c7cd0 miniruby`co_start(from=<unavailable>, self=0x0000aaab9df0f760) at thread_pthread_mn.c:421:9
```
  • Loading branch information
ko1 committed Oct 14, 2023
1 parent 16d14f4 commit eb79b03
Showing 1 changed file with 10 additions and 2 deletions.
12 changes: 10 additions & 2 deletions thread_pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,16 @@ thread_sched_setup_running_threads(struct rb_thread_sched *sched, rb_ractor_t *c

if (add_th && !del_th && UNLIKELY(vm->ractor.sync.lock_owner != NULL)) {
// it can be after barrier synchronization by another ractor
RB_VM_LOCK_ENTER();
RB_VM_LOCK_LEAVE();
rb_thread_t *lock_owner = NULL;
#if VM_CHECK_MODE
lock_owner = sched->lock_owner;
#endif
thread_sched_unlock(sched, lock_owner);
{
RB_VM_LOCK_ENTER();
RB_VM_LOCK_LEAVE();
}
thread_sched_lock(sched, lock_owner);
}

//RUBY_DEBUG_LOG("+:%u -:%u +ts:%u -ts:%u run:%u->%u",
Expand Down

0 comments on commit eb79b03

Please sign in to comment.