Ruby 3.5.0dev (2025-05-21 revision 081a44f586b19e66be5a22d2f7d29b34de453efb)
ractor_core.h (081a44f586b19e66be5a22d2f7d29b34de453efb)
1#include "internal/gc.h"
2#include "ruby/ruby.h"
3#include "ruby/ractor.h"
4#include "vm_core.h"
5#include "id_table.h"
6#include "vm_debug.h"
7
8#ifndef RACTOR_CHECK_MODE
9#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
10#endif
11
12enum rb_ractor_basket_type {
13 // basket is empty
14 basket_type_none,
15
16 // value is available
17 basket_type_ref,
18 basket_type_copy,
19 basket_type_move,
20 basket_type_will,
21
22 // basket should be deleted
23 basket_type_deleted,
24
25 // basket is reserved
26 basket_type_reserved,
27
28 // take_basket is available
29 basket_type_take_basket,
30
31 // basket is keeping by yielding ractor
32 basket_type_yielding,
33};
34
35// per ractor taking configuration
37 bool closed;
38 bool oneshot;
39};
40
42 union {
43 enum rb_ractor_basket_type e;
44 rb_atomic_t atomic;
45 } type;
46 VALUE sender; // Ractor object sending message
47 rb_thread_t *sending_th;
48
49 union {
50 struct {
51 VALUE v;
52 bool exception;
53 } send;
54
55 struct {
56 struct rb_ractor_basket *basket;
57 struct rb_ractor_selector_take_config *config;
58 } take;
59 } p; // payload
60};
61
62static inline bool
63basket_type_p(struct rb_ractor_basket *b, enum rb_ractor_basket_type type)
64{
65 return b->type.e == type;
66}
67
68static inline bool
69basket_none_p(struct rb_ractor_basket *b)
70{
71 return basket_type_p(b, basket_type_none);
72}
73
75 struct rb_ractor_basket *baskets;
76 int start;
77 int cnt;
78 int size;
79 unsigned int serial;
80 unsigned int reserved_cnt;
81};
82
83enum rb_ractor_wait_status {
84 wait_none = 0x00,
85 wait_receiving = 0x01,
86 wait_taking = 0x02,
87 wait_yielding = 0x04,
88 wait_moving = 0x08,
89};
90
91enum rb_ractor_wakeup_status {
92 wakeup_none,
93 wakeup_by_send,
94 wakeup_by_yield,
95 wakeup_by_take,
96 wakeup_by_close,
97 wakeup_by_interrupt,
98 wakeup_by_retry,
99};
100
102 // ractor lock
103 rb_nativethread_lock_t lock;
104#if RACTOR_CHECK_MODE > 0
105 VALUE locked_by;
106#endif
107
108 bool incoming_port_closed;
109 bool outgoing_port_closed;
110
111 // All sent messages will be pushed into recv_queue
112 struct rb_ractor_queue recv_queue;
113
114 // The following ractors waiting for the yielding by this ractor
115 struct rb_ractor_queue takers_queue;
116
117 // Enabled if the ractor already terminated and not taken yet.
118 struct rb_ractor_basket will_basket;
119
120 struct ractor_wait {
121 struct ccan_list_head waiting_threads;
122 // each thread has struct ccan_list_node ractor_waiting.waiting_node
123 } wait;
124};
125
126// created
127// | ready to run
128// ====================== inserted to vm->ractor
129// v
130// blocking <---+ all threads are blocking
131// | |
132// v |
133// running -----+
134// | all threads are terminated.
135// ====================== removed from vm->ractor
136// v
137// terminated
138//
139// status is protected by VM lock (global state)
140enum ractor_status {
141 ractor_created,
142 ractor_running,
143 ractor_blocking,
144 ractor_terminated,
145};
146
148 struct rb_ractor_pub pub;
149
150 struct rb_ractor_sync sync;
151
152 // vm wide barrier synchronization
153 rb_nativethread_cond_t barrier_wait_cond;
154
155 // thread management
156 struct {
157 struct ccan_list_head set;
158 unsigned int cnt;
159 unsigned int blocking_cnt;
160 unsigned int sleeper;
161 struct rb_thread_sched sched;
162 rb_execution_context_t *running_ec;
163 rb_thread_t *main;
164 } threads;
165 VALUE thgroup_default;
166
167 VALUE name;
168 VALUE loc;
169
170 enum ractor_status status_;
171
172 struct ccan_list_node vmlr_node;
173
174 // ractor local data
175
176 st_table *local_storage;
177 struct rb_id_table *idkey_local_storage;
178 VALUE local_storage_store_lock;
179
180 VALUE r_stdin;
181 VALUE r_stdout;
182 VALUE r_stderr;
183 VALUE verbose;
184 VALUE debug;
185
186 void *newobj_cache;
187}; // rb_ractor_t is defined in vm_core.h
188
189
190static inline VALUE
191rb_ractor_self(const rb_ractor_t *r)
192{
193 return r->pub.self;
194}
195
196rb_ractor_t *rb_ractor_main_alloc(void);
197void rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *main_ractor, rb_thread_t *main_thread);
198void rb_ractor_atexit(rb_execution_context_t *ec, VALUE result);
199void rb_ractor_atexit_exception(rb_execution_context_t *ec);
200void rb_ractor_teardown(rb_execution_context_t *ec);
201void rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *g, int len, VALUE *ptr);
202void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE args);
203
204VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
205
206int rb_ractor_living_thread_num(const rb_ractor_t *);
207VALUE rb_ractor_thread_list(void);
208bool rb_ractor_p(VALUE rv);
209
210void rb_ractor_living_threads_init(rb_ractor_t *r);
211void rb_ractor_living_threads_insert(rb_ractor_t *r, rb_thread_t *th);
212void rb_ractor_living_threads_remove(rb_ractor_t *r, rb_thread_t *th);
213void rb_ractor_blocking_threads_inc(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
214void rb_ractor_blocking_threads_dec(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
215
216void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r);
217void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
218void rb_ractor_terminate_all(void);
219bool rb_ractor_main_p_(void);
220void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
221void rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *th);
222VALUE rb_ractor_require(VALUE feature);
223VALUE rb_ractor_autoload_load(VALUE space, ID id);
224
225VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
226
227RUBY_SYMBOL_EXPORT_BEGIN
228void rb_ractor_finish_marking(void);
229
230bool rb_ractor_shareable_p_continue(VALUE obj);
231
232// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
233// This function is for T_DATA::free_func
234void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key);
235
236RUBY_SYMBOL_EXPORT_END
237
238static inline bool
239rb_ractor_main_p(void)
240{
241 if (ruby_single_main_ractor) {
242 return true;
243 }
244 else {
245 return rb_ractor_main_p_();
246 }
247}
248
249static inline bool
250rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status)
251{
252 return r->status_ == status;
253}
254
255static inline void
256rb_ractor_sleeper_threads_inc(rb_ractor_t *r)
257{
258 r->threads.sleeper++;
259}
260
261static inline void
262rb_ractor_sleeper_threads_dec(rb_ractor_t *r)
263{
264 r->threads.sleeper--;
265}
266
267static inline void
268rb_ractor_sleeper_threads_clear(rb_ractor_t *r)
269{
270 r->threads.sleeper = 0;
271}
272
273static inline int
274rb_ractor_sleeper_thread_num(rb_ractor_t *r)
275{
276 return r->threads.sleeper;
277}
278
279static inline void
280rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th, bool always_reset)
281{
282 RUBY_DEBUG_LOG("th:%d->%u%s",
283 cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1,
284 rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : "");
285
286 if (cr->threads.running_ec != th->ec || always_reset) {
287 th->running_time_us = 0;
288 }
289
290 if (cr->threads.running_ec != th->ec) {
291 if (0) {
292 ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
293 (void *)cr->threads.running_ec, (void *)th->ec);
294 }
295 }
296 else {
297 return;
298 }
299
300 cr->threads.running_ec = th->ec;
301
302 VM_ASSERT(cr == GET_RACTOR());
303}
304
305#define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__)
306#ifdef RB_THREAD_LOCAL_SPECIFIER
307void rb_current_ec_set(rb_execution_context_t *ec);
308#endif
309
310static inline void
311rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
312{
313#ifdef RB_THREAD_LOCAL_SPECIFIER
314 rb_current_ec_set(ec);
315#else
316 native_tls_set(ruby_current_ec_key, ec);
317#endif
318 RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
319 VM_ASSERT(ec == NULL || cr->threads.running_ec != ec);
320 cr->threads.running_ec = ec;
321}
322
323void rb_vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
324void rb_vm_ractor_blocking_cnt_dec(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
325
326static inline uint32_t
327rb_ractor_id(const rb_ractor_t *r)
328{
329 return r->pub.id;
330}
331
332#if RACTOR_CHECK_MODE > 0
333# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
334
335uint32_t rb_ractor_current_id(void);
336
337static inline void
338rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
339{
340 RACTOR_BELONGING_ID(obj) = rid;
341}
342
343static inline uint32_t
344rb_ractor_belonging(VALUE obj)
345{
346 if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) {
347 return 0;
348 }
349 else {
350 return RACTOR_BELONGING_ID(obj);
351 }
352}
353
354static inline VALUE
355rb_ractor_confirm_belonging(VALUE obj)
356{
357 uint32_t id = rb_ractor_belonging(obj);
358
359 if (id == 0) {
360 if (UNLIKELY(!rb_ractor_shareable_p(obj))) {
361 rp(obj);
362 rb_bug("id == 0 but not shareable");
363 }
364 }
365 else if (UNLIKELY(id != rb_ractor_current_id())) {
366 if (rb_ractor_shareable_p(obj)) {
367 // ok
368 }
369 else {
370 rp(obj);
371 rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id());
372 }
373 }
374 return obj;
375}
376#else
377#define rb_ractor_confirm_belonging(obj) obj
378#endif
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
int len
Length of the buffer.
Definition io.h:8
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
Definition ractor.h:249
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition st.h:79
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40