1 #include "internal/gc.h"
2 #include "internal/thread.h"
5 #include "ractor_core.h"
8 void rb_ractor_sched_barrier_start(rb_vm_t
*vm
, rb_ractor_t
*cr
);
9 void rb_ractor_sched_barrier_join(rb_vm_t
*vm
, rb_ractor_t
*cr
);
12 vm_locked(rb_vm_t
*vm
)
14 return vm
->ractor
.sync
.lock_owner
== GET_RACTOR();
19 RUBY_ASSERT_vm_locking(void)
21 if (rb_multi_ractor_p()) {
22 rb_vm_t
*vm
= GET_VM();
23 VM_ASSERT(vm_locked(vm
));
28 RUBY_ASSERT_vm_unlocking(void)
30 if (rb_multi_ractor_p()) {
31 rb_vm_t
*vm
= GET_VM();
32 VM_ASSERT(!vm_locked(vm
));
40 return vm_locked(GET_VM());
44 vm_lock_enter(rb_ractor_t
*cr
, rb_vm_t
*vm
, bool locked
, bool no_barrier
, unsigned int *lev APPEND_LOCATION_ARGS
)
46 RUBY_DEBUG_LOG2(file
, line
, "start locked:%d", locked
);
53 // locking ractor and acquire VM lock will cause deadlock
54 VM_ASSERT(cr
->sync
.locked_by
!= rb_ractor_self(cr
));
57 rb_native_mutex_lock(&vm
->ractor
.sync
.lock
);
58 VM_ASSERT(vm
->ractor
.sync
.lock_owner
== NULL
);
59 VM_ASSERT(vm
->ractor
.sync
.lock_rec
== 0);
61 #ifdef RUBY_THREAD_PTHREAD_H
63 cr
->threads
.sched
.running
!= NULL
// ractor has running threads.
66 while (vm
->ractor
.sched
.barrier_waiting
) {
67 RUBY_DEBUG_LOG("barrier serial:%u", vm
->ractor
.sched
.barrier_serial
);
68 rb_ractor_sched_barrier_join(vm
, cr
);
73 while (vm
->ractor
.sync
.barrier_waiting
) {
74 rb_ractor_sched_barrier_join(vm
, cr
);
79 VM_ASSERT(vm
->ractor
.sync
.lock_rec
== 0);
80 VM_ASSERT(vm
->ractor
.sync
.lock_owner
== NULL
);
81 vm
->ractor
.sync
.lock_owner
= cr
;
84 vm
->ractor
.sync
.lock_rec
++;
85 *lev
= vm
->ractor
.sync
.lock_rec
;
87 RUBY_DEBUG_LOG2(file
, line
, "rec:%u owner:%u", vm
->ractor
.sync
.lock_rec
,
88 (unsigned int)rb_ractor_id(vm
->ractor
.sync
.lock_owner
));
92 vm_lock_leave(rb_vm_t
*vm
, unsigned int *lev APPEND_LOCATION_ARGS
)
94 RUBY_DEBUG_LOG2(file
, line
, "rec:%u owner:%u%s", vm
->ractor
.sync
.lock_rec
,
95 (unsigned int)rb_ractor_id(vm
->ractor
.sync
.lock_owner
),
96 vm
->ractor
.sync
.lock_rec
== 1 ? " (leave)" : "");
99 VM_ASSERT(vm
->ractor
.sync
.lock_rec
> 0);
100 VM_ASSERT(vm
->ractor
.sync
.lock_rec
== *lev
);
102 vm
->ractor
.sync
.lock_rec
--;
103 *lev
= vm
->ractor
.sync
.lock_rec
;
105 if (vm
->ractor
.sync
.lock_rec
== 0) {
106 vm
->ractor
.sync
.lock_owner
= NULL
;
107 rb_native_mutex_unlock(&vm
->ractor
.sync
.lock
);
112 rb_vm_lock_enter_body(unsigned int *lev APPEND_LOCATION_ARGS
)
114 rb_vm_t
*vm
= GET_VM();
116 vm_lock_enter(NULL
, vm
, true, false, lev APPEND_LOCATION_PARAMS
);
119 vm_lock_enter(GET_RACTOR(), vm
, false, false, lev APPEND_LOCATION_PARAMS
);
124 rb_vm_lock_enter_body_nb(unsigned int *lev APPEND_LOCATION_ARGS
)
126 rb_vm_t
*vm
= GET_VM();
128 vm_lock_enter(NULL
, vm
, true, true, lev APPEND_LOCATION_PARAMS
);
131 vm_lock_enter(GET_RACTOR(), vm
, false, true, lev APPEND_LOCATION_PARAMS
);
136 rb_vm_lock_enter_body_cr(rb_ractor_t
*cr
, unsigned int *lev APPEND_LOCATION_ARGS
)
138 rb_vm_t
*vm
= GET_VM();
139 vm_lock_enter(cr
, vm
, vm_locked(vm
), false, lev APPEND_LOCATION_PARAMS
);
143 rb_vm_lock_leave_body(unsigned int *lev APPEND_LOCATION_ARGS
)
145 vm_lock_leave(GET_VM(), lev APPEND_LOCATION_PARAMS
);
149 rb_vm_lock_body(LOCATION_ARGS
)
151 rb_vm_t
*vm
= GET_VM();
152 ASSERT_vm_unlocking();
154 vm_lock_enter(GET_RACTOR(), vm
, false, false, &vm
->ractor
.sync
.lock_rec APPEND_LOCATION_PARAMS
);
158 rb_vm_unlock_body(LOCATION_ARGS
)
160 rb_vm_t
*vm
= GET_VM();
162 VM_ASSERT(vm
->ractor
.sync
.lock_rec
== 1);
163 vm_lock_leave(vm
, &vm
->ractor
.sync
.lock_rec APPEND_LOCATION_PARAMS
);
167 vm_cond_wait(rb_vm_t
*vm
, rb_nativethread_cond_t
*cond
, unsigned long msec
)
170 unsigned int lock_rec
= vm
->ractor
.sync
.lock_rec
;
171 rb_ractor_t
*cr
= vm
->ractor
.sync
.lock_owner
;
173 vm
->ractor
.sync
.lock_rec
= 0;
174 vm
->ractor
.sync
.lock_owner
= NULL
;
176 rb_native_cond_timedwait(cond
, &vm
->ractor
.sync
.lock
, msec
);
179 rb_native_cond_wait(cond
, &vm
->ractor
.sync
.lock
);
181 vm
->ractor
.sync
.lock_rec
= lock_rec
;
182 vm
->ractor
.sync
.lock_owner
= cr
;
186 rb_vm_cond_wait(rb_vm_t
*vm
, rb_nativethread_cond_t
*cond
)
188 vm_cond_wait(vm
, cond
, 0);
192 rb_vm_cond_timedwait(rb_vm_t
*vm
, rb_nativethread_cond_t
*cond
, unsigned long msec
)
194 vm_cond_wait(vm
, cond
, msec
);
200 RB_DEBUG_COUNTER_INC(vm_sync_barrier
);
202 if (!rb_multi_ractor_p()) {
207 rb_vm_t
*vm
= GET_VM();
208 VM_ASSERT(!vm
->ractor
.sched
.barrier_waiting
);
210 rb_ractor_t
*cr
= vm
->ractor
.sync
.lock_owner
;
211 VM_ASSERT(cr
== GET_RACTOR());
212 VM_ASSERT(rb_ractor_status_p(cr
, ractor_running
));
214 rb_ractor_sched_barrier_start(vm
, cr
);
219 rb_ec_vm_lock_rec_release(const rb_execution_context_t
*ec
,
220 unsigned int recorded_lock_rec
,
221 unsigned int current_lock_rec
)
223 VM_ASSERT(recorded_lock_rec
!= current_lock_rec
);
225 if (UNLIKELY(recorded_lock_rec
> current_lock_rec
)) {
226 rb_bug("unexpected situation - recordd:%u current:%u",
227 recorded_lock_rec
, current_lock_rec
);
230 while (recorded_lock_rec
< current_lock_rec
) {
231 RB_VM_LOCK_LEAVE_LEV(¤t_lock_rec
);
235 VM_ASSERT(recorded_lock_rec
== rb_ec_vm_lock_rec(ec
));