1 #include "internal/gc.h"
3 #include "ruby/ractor.h"
8 #ifndef RACTOR_CHECK_MODE
9 #define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
12 enum rb_ractor_basket_type
{
22 // basket should be deleted
28 // take_basket is available
29 basket_type_take_basket
,
31 // basket is keeping by yielding ractor
35 // per ractor taking configuration
36 struct rb_ractor_selector_take_config
{
41 struct rb_ractor_basket
{
43 enum rb_ractor_basket_type e
;
55 struct rb_ractor_basket
*basket
;
56 struct rb_ractor_selector_take_config
*config
;
62 basket_type_p(struct rb_ractor_basket
*b
, enum rb_ractor_basket_type type
)
64 return b
->type
.e
== type
;
68 basket_none_p(struct rb_ractor_basket
*b
)
70 return basket_type_p(b
, basket_type_none
);
73 struct rb_ractor_queue
{
74 struct rb_ractor_basket
*baskets
;
79 unsigned int reserved_cnt
;
82 enum rb_ractor_wait_status
{
84 wait_receiving
= 0x01,
90 enum rb_ractor_wakeup_status
{
100 struct rb_ractor_sync
{
102 rb_nativethread_lock_t lock
;
103 #if RACTOR_CHECK_MODE > 0
107 bool incoming_port_closed
;
108 bool outgoing_port_closed
;
110 // All sent messages will be pushed into recv_queue
111 struct rb_ractor_queue recv_queue
;
113 // The following ractors waiting for the yielding by this ractor
114 struct rb_ractor_queue takers_queue
;
116 // Enabled if the ractor already terminated and not taken yet.
117 struct rb_ractor_basket will_basket
;
120 enum rb_ractor_wait_status status
;
121 enum rb_ractor_wakeup_status wakeup_status
;
122 rb_thread_t
*waiting_thread
;
125 #ifndef RUBY_THREAD_PTHREAD_H
126 rb_nativethread_cond_t cond
;
132 // ====================== inserted to vm->ractor
134 // blocking <---+ all threads are blocking
138 // | all threads are terminated.
139 // ====================== removed from vm->ractor
143 // status is protected by VM lock (global state)
151 struct rb_ractor_struct
{
152 struct rb_ractor_pub pub
;
154 struct rb_ractor_sync sync
;
155 VALUE receiving_mutex
;
157 // vm wide barrier synchronization
158 rb_nativethread_cond_t barrier_wait_cond
;
162 struct ccan_list_head set
;
164 unsigned int blocking_cnt
;
165 unsigned int sleeper
;
166 struct rb_thread_sched sched
;
167 rb_execution_context_t
*running_ec
;
170 VALUE thgroup_default
;
175 enum ractor_status status_
;
177 struct ccan_list_node vmlr_node
;
181 st_table
*local_storage
;
182 struct rb_id_table
*idkey_local_storage
;
190 rb_ractor_newobj_cache_t newobj_cache
;
192 // gc.c rb_objspace_reachable_objects_from
193 struct gc_mark_func_data_struct
{
195 void (*mark_func
)(VALUE v
, void *data
);
197 }; // rb_ractor_t is defined in vm_core.h
201 rb_ractor_self(const rb_ractor_t
*r
)
206 rb_ractor_t
*rb_ractor_main_alloc(void);
207 void rb_ractor_main_setup(rb_vm_t
*vm
, rb_ractor_t
*main_ractor
, rb_thread_t
*main_thread
);
208 void rb_ractor_atexit(rb_execution_context_t
*ec
, VALUE result
);
209 void rb_ractor_atexit_exception(rb_execution_context_t
*ec
);
210 void rb_ractor_teardown(rb_execution_context_t
*ec
);
211 void rb_ractor_receive_parameters(rb_execution_context_t
*ec
, rb_ractor_t
*g
, int len
, VALUE
*ptr
);
212 void rb_ractor_send_parameters(rb_execution_context_t
*ec
, rb_ractor_t
*g
, VALUE args
);
214 VALUE
rb_thread_create_ractor(rb_ractor_t
*g
, VALUE args
, VALUE proc
); // defined in thread.c
216 int rb_ractor_living_thread_num(const rb_ractor_t
*);
217 VALUE
rb_ractor_thread_list(void);
218 bool rb_ractor_p(VALUE rv
);
220 void rb_ractor_living_threads_init(rb_ractor_t
*r
);
221 void rb_ractor_living_threads_insert(rb_ractor_t
*r
, rb_thread_t
*th
);
222 void rb_ractor_living_threads_remove(rb_ractor_t
*r
, rb_thread_t
*th
);
223 void rb_ractor_blocking_threads_inc(rb_ractor_t
*r
, const char *file
, int line
); // TODO: file, line only for RUBY_DEBUG_LOG
224 void rb_ractor_blocking_threads_dec(rb_ractor_t
*r
, const char *file
, int line
); // TODO: file, line only for RUBY_DEBUG_LOG
226 void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t
*r
);
227 void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t
*r
);
228 void rb_ractor_terminate_all(void);
229 bool rb_ractor_main_p_(void);
230 void rb_ractor_finish_marking(void);
231 void rb_ractor_atfork(rb_vm_t
*vm
, rb_thread_t
*th
);
233 VALUE
rb_ractor_ensure_shareable(VALUE obj
, VALUE name
);
235 RUBY_SYMBOL_EXPORT_BEGIN
236 bool rb_ractor_shareable_p_continue(VALUE obj
);
238 // THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
239 // This function is for T_DATA::free_func
240 void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key
);
242 RUBY_SYMBOL_EXPORT_END
245 rb_ractor_main_p(void)
247 if (ruby_single_main_ractor
) {
251 return rb_ractor_main_p_();
256 rb_ractor_status_p(rb_ractor_t
*r
, enum ractor_status status
)
258 return r
->status_
== status
;
262 rb_ractor_sleeper_threads_inc(rb_ractor_t
*r
)
264 r
->threads
.sleeper
++;
268 rb_ractor_sleeper_threads_dec(rb_ractor_t
*r
)
270 r
->threads
.sleeper
--;
274 rb_ractor_sleeper_threads_clear(rb_ractor_t
*r
)
276 r
->threads
.sleeper
= 0;
280 rb_ractor_sleeper_thread_num(rb_ractor_t
*r
)
282 return r
->threads
.sleeper
;
286 rb_ractor_thread_switch(rb_ractor_t
*cr
, rb_thread_t
*th
)
288 RUBY_DEBUG_LOG("th:%d->%u%s",
289 cr
->threads
.running_ec
? (int)rb_th_serial(cr
->threads
.running_ec
->thread_ptr
) : -1,
290 rb_th_serial(th
), cr
->threads
.running_ec
== th
->ec
? " (same)" : "");
292 if (cr
->threads
.running_ec
!= th
->ec
) {
294 ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
295 (void *)cr
->threads
.running_ec
, (void *)th
->ec
);
302 if (cr
->threads
.running_ec
!= th
->ec
) {
303 th
->running_time_us
= 0;
306 cr
->threads
.running_ec
= th
->ec
;
308 VM_ASSERT(cr
== GET_RACTOR());
311 #define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__)
314 rb_ractor_set_current_ec_(rb_ractor_t
*cr
, rb_execution_context_t
*ec
, const char *file
, int line
)
316 #ifdef RB_THREAD_LOCAL_SPECIFIER
319 rb_current_ec_set(ec
);
321 ruby_current_ec
= ec
;
325 native_tls_set(ruby_current_ec_key
, ec
);
327 RUBY_DEBUG_LOG2(file
, line
, "ec:%p->%p", (void *)cr
->threads
.running_ec
, (void *)ec
);
328 VM_ASSERT(ec
== NULL
|| cr
->threads
.running_ec
!= ec
);
329 cr
->threads
.running_ec
= ec
;
332 void rb_vm_ractor_blocking_cnt_inc(rb_vm_t
*vm
, rb_ractor_t
*cr
, const char *file
, int line
);
333 void rb_vm_ractor_blocking_cnt_dec(rb_vm_t
*vm
, rb_ractor_t
*cr
, const char *file
, int line
);
335 static inline uint32_t
336 rb_ractor_id(const rb_ractor_t
*r
)
341 #if RACTOR_CHECK_MODE > 0
342 # define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
344 uint32_t rb_ractor_current_id(void);
347 rb_ractor_setup_belonging_to(VALUE obj
, uint32_t rid
)
349 RACTOR_BELONGING_ID(obj
) = rid
;
353 rb_ractor_setup_belonging(VALUE obj
)
355 rb_ractor_setup_belonging_to(obj
, rb_ractor_current_id());
358 static inline uint32_t
359 rb_ractor_belonging(VALUE obj
)
361 if (SPECIAL_CONST_P(obj
) || RB_OBJ_SHAREABLE_P(obj
)) {
365 return RACTOR_BELONGING_ID(obj
);
370 rb_ractor_confirm_belonging(VALUE obj
)
372 uint32_t id
= rb_ractor_belonging(obj
);
375 if (UNLIKELY(!rb_ractor_shareable_p(obj
))) {
377 rb_bug("id == 0 but not shareable");
380 else if (UNLIKELY(id
!= rb_ractor_current_id())) {
381 if (rb_ractor_shareable_p(obj
)) {
386 rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id
, rb_ractor_current_id());
392 #define rb_ractor_confirm_belonging(obj) obj