2 #include "ruby/ractor.h"
7 #ifndef RACTOR_CHECK_MODE
8 #define RACTOR_CHECK_MODE (0 || VM_CHECK_MODE || RUBY_DEBUG)
11 enum rb_ractor_basket_type
{
21 struct rb_ractor_basket
{
23 enum rb_ractor_basket_type type
;
28 struct rb_ractor_queue
{
29 struct rb_ractor_basket
*baskets
;
34 unsigned int reserved_cnt
;
37 struct rb_ractor_waiting_list
{
40 rb_ractor_t
**ractors
;
43 struct rb_ractor_sync
{
45 rb_nativethread_lock_t lock
;
46 #if RACTOR_CHECK_MODE > 0
49 rb_nativethread_cond_t cond
;
52 struct rb_ractor_queue incoming_queue
;
53 struct rb_ractor_waiting_list taking_ractors
;
55 bool incoming_port_closed
;
56 bool outgoing_port_closed
;
59 enum ractor_wait_status
{
61 wait_receiving
= 0x01,
67 enum ractor_wakeup_status
{
77 struct rb_ractor_basket yielded_basket
;
78 struct rb_ractor_basket taken_basket
;
82 struct rb_ractor_struct
{
83 struct rb_ractor_pub pub
;
85 struct rb_ractor_sync sync
;
86 VALUE receiving_mutex
;
89 // vm wide barrier synchronization
90 rb_nativethread_cond_t barrier_wait_cond
;
96 unsigned int blocking_cnt
;
98 rb_global_vm_lock_t gvl
;
99 rb_execution_context_t
*running_ec
;
102 VALUE thgroup_default
;
109 // ====================== inserted to vm->ractor
111 // blocking <---+ all threads are blocking
115 // | all threads are terminated.
116 // ====================== removed from vm->ractor
120 // status is protected by VM lock (global state)
129 struct list_node vmlr_node
;
133 st_table
*local_storage
;
134 struct rb_id_table
*idkey_local_storage
;
142 rb_ractor_newobj_cache_t newobj_cache
;
144 // gc.c rb_objspace_reachable_objects_from
145 struct gc_mark_func_data_struct
{
147 void (*mark_func
)(VALUE v
, void *data
);
149 }; // rb_ractor_t is defined in vm_core.h
153 rb_ractor_self(const rb_ractor_t
*r
)
158 rb_ractor_t
*rb_ractor_main_alloc(void);
159 void rb_ractor_main_setup(rb_vm_t
*vm
, rb_ractor_t
*main_ractor
, rb_thread_t
*main_thread
);
160 void rb_ractor_atexit(rb_execution_context_t
*ec
, VALUE result
);
161 void rb_ractor_atexit_exception(rb_execution_context_t
*ec
);
162 void rb_ractor_teardown(rb_execution_context_t
*ec
);
163 void rb_ractor_receive_parameters(rb_execution_context_t
*ec
, rb_ractor_t
*g
, int len
, VALUE
*ptr
);
164 void rb_ractor_send_parameters(rb_execution_context_t
*ec
, rb_ractor_t
*g
, VALUE args
);
166 VALUE
rb_thread_create_ractor(rb_ractor_t
*g
, VALUE args
, VALUE proc
); // defined in thread.c
168 rb_global_vm_lock_t
*rb_ractor_gvl(rb_ractor_t
*);
169 int rb_ractor_living_thread_num(const rb_ractor_t
*);
170 VALUE
rb_ractor_thread_list(rb_ractor_t
*r
);
171 bool rb_ractor_p(VALUE rv
);
173 void rb_ractor_living_threads_init(rb_ractor_t
*r
);
174 void rb_ractor_living_threads_insert(rb_ractor_t
*r
, rb_thread_t
*th
);
175 void rb_ractor_living_threads_remove(rb_ractor_t
*r
, rb_thread_t
*th
);
176 void rb_ractor_blocking_threads_inc(rb_ractor_t
*r
, const char *file
, int line
); // TODO: file, line only for RUBY_DEBUG_LOG
177 void rb_ractor_blocking_threads_dec(rb_ractor_t
*r
, const char *file
, int line
); // TODO: file, line only for RUBY_DEBUG_LOG
179 void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t
*r
);
180 void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t
*r
);
181 void rb_ractor_terminate_all(void);
182 bool rb_ractor_main_p_(void);
183 void rb_ractor_finish_marking(void);
184 void rb_ractor_atfork(rb_vm_t
*vm
, rb_thread_t
*th
);
186 VALUE
rb_ractor_ensure_shareable(VALUE obj
, VALUE name
);
188 RUBY_SYMBOL_EXPORT_BEGIN
189 bool rb_ractor_shareable_p_continue(VALUE obj
);
191 // THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
192 // This function is for T_DATA::free_func
193 void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key
);
195 RUBY_SYMBOL_EXPORT_END
198 rb_ractor_main_p(void)
200 if (ruby_single_main_ractor
) {
204 return rb_ractor_main_p_();
209 rb_ractor_status_p(rb_ractor_t
*r
, enum ractor_status status
)
211 return r
->status_
== status
;
215 rb_ractor_sleeper_threads_inc(rb_ractor_t
*r
)
217 r
->threads
.sleeper
++;
221 rb_ractor_sleeper_threads_dec(rb_ractor_t
*r
)
223 r
->threads
.sleeper
--;
227 rb_ractor_sleeper_threads_clear(rb_ractor_t
*r
)
229 r
->threads
.sleeper
= 0;
233 rb_ractor_sleeper_thread_num(rb_ractor_t
*r
)
235 return r
->threads
.sleeper
;
239 rb_ractor_thread_switch(rb_ractor_t
*cr
, rb_thread_t
*th
)
241 if (cr
->threads
.running_ec
!= th
->ec
) {
243 ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
244 (void *)cr
->threads
.running_ec
, (void *)th
->ec
);
251 if (cr
->threads
.running_ec
!= th
->ec
) {
252 th
->running_time_us
= 0;
255 cr
->threads
.running_ec
= th
->ec
;
257 VM_ASSERT(cr
== GET_RACTOR());
261 rb_ractor_set_current_ec(rb_ractor_t
*cr
, rb_execution_context_t
*ec
)
263 #ifdef RB_THREAD_LOCAL_SPECIFIER
265 rb_current_ec_set(ec
);
267 ruby_current_ec
= ec
;
270 native_tls_set(ruby_current_ec_key
, ec
);
273 if (cr
->threads
.running_ec
!= ec
) {
275 ruby_debug_printf("rb_ractor_set_current_ec ec:%p->%p\n",
276 (void *)cr
->threads
.running_ec
, (void *)ec
);
280 VM_ASSERT(0); // should be different
283 cr
->threads
.running_ec
= ec
;
286 void rb_vm_ractor_blocking_cnt_inc(rb_vm_t
*vm
, rb_ractor_t
*cr
, const char *file
, int line
);
287 void rb_vm_ractor_blocking_cnt_dec(rb_vm_t
*vm
, rb_ractor_t
*cr
, const char *file
, int line
);
289 static inline uint32_t
290 rb_ractor_id(const rb_ractor_t
*r
)
295 #if RACTOR_CHECK_MODE > 0
296 uint32_t rb_ractor_current_id(void);
299 rb_ractor_setup_belonging_to(VALUE obj
, uint32_t rid
)
301 VALUE flags
= RBASIC(obj
)->flags
& 0xffffffff; // 4B
302 RBASIC(obj
)->flags
= flags
| ((VALUE
)rid
<< 32);
306 rb_ractor_setup_belonging(VALUE obj
)
308 rb_ractor_setup_belonging_to(obj
, rb_ractor_current_id());
311 static inline uint32_t
312 rb_ractor_belonging(VALUE obj
)
314 if (SPECIAL_CONST_P(obj
) || RB_OBJ_SHAREABLE_P(obj
)) {
318 return RBASIC(obj
)->flags
>> 32;
323 rb_ractor_confirm_belonging(VALUE obj
)
325 uint32_t id
= rb_ractor_belonging(obj
);
328 if (UNLIKELY(!rb_ractor_shareable_p(obj
))) {
330 rb_bug("id == 0 but not shareable");
333 else if (UNLIKELY(id
!= rb_ractor_current_id())) {
334 if (rb_ractor_shareable_p(obj
)) {
339 rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id
, rb_ractor_current_id());
345 #define rb_ractor_confirm_belonging(obj) obj