Ruby 3.5.0dev (2025-09-05 revision 5d6d8568ab8ad80ab75ce1b914644f179714e7cf)
ractor_core.h (5d6d8568ab8ad80ab75ce1b914644f179714e7cf)
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
13 // ractor lock
14 rb_nativethread_lock_t lock;
15
16#if RACTOR_CHECK_MODE > 0
17 VALUE locked_by;
18#endif
19
20#ifndef RUBY_THREAD_PTHREAD_H
21 rb_nativethread_cond_t wakeup_cond;
22#endif
23
24 // incoming messages
25 struct ractor_queue *recv_queue;
26
27 // waiting threads for receiving
28 struct ccan_list_head waiters;
29
30 // ports
31 VALUE default_port_value;
32 struct st_table *ports;
33 size_t next_port_id;
34
35 // monitors
36 struct ccan_list_head monitors;
37
38 // value
39 rb_ractor_t *successor;
40 VALUE legacy;
41 bool legacy_exc;
42};
43
44// created
45// | ready to run
46// ====================== inserted to vm->ractor
47// v
48// blocking <---+ all threads are blocking
49// | |
50// v |
51// running -----+
52// | all threads are terminated.
53// ====================== removed from vm->ractor
54// v
55// terminated
56//
57// status is protected by VM lock (global state)
58enum ractor_status {
59 ractor_created,
60 ractor_running,
61 ractor_blocking,
62 ractor_terminated,
63};
64
66 struct rb_ractor_pub pub;
67 struct rb_ractor_sync sync;
68
69 // thread management
70 struct {
71 struct ccan_list_head set;
72 unsigned int cnt;
73 unsigned int blocking_cnt;
74 unsigned int sleeper;
75 struct rb_thread_sched sched;
76 rb_execution_context_t *running_ec;
77 rb_thread_t *main;
78 } threads;
79
80 VALUE thgroup_default;
81
82 VALUE name;
83 VALUE loc;
84
85 enum ractor_status status_;
86
87 struct ccan_list_node vmlr_node;
88
89 // ractor local data
90
91 st_table *local_storage;
92 struct rb_id_table *idkey_local_storage;
93 VALUE local_storage_store_lock;
94
95 VALUE r_stdin;
96 VALUE r_stdout;
97 VALUE r_stderr;
98 VALUE verbose;
99 VALUE debug;
100
101 bool malloc_gc_disabled;
102 void *newobj_cache;
103}; // rb_ractor_t is defined in vm_core.h
104
105
106static inline VALUE
107rb_ractor_self(const rb_ractor_t *r)
108{
109 return r->pub.self;
110}
111
112rb_ractor_t *rb_ractor_main_alloc(void);
113void rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *main_ractor, rb_thread_t *main_thread);
114void rb_ractor_atexit(rb_execution_context_t *ec, VALUE result);
115void rb_ractor_atexit_exception(rb_execution_context_t *ec);
116void rb_ractor_teardown(rb_execution_context_t *ec);
117void rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *g, int len, VALUE *ptr);
118void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE args);
119
120VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
121
122int rb_ractor_living_thread_num(const rb_ractor_t *);
123VALUE rb_ractor_thread_list(void);
124bool rb_ractor_p(VALUE rv);
125
126void rb_ractor_living_threads_init(rb_ractor_t *r);
127void rb_ractor_living_threads_insert(rb_ractor_t *r, rb_thread_t *th);
128void rb_ractor_living_threads_remove(rb_ractor_t *r, rb_thread_t *th);
129void rb_ractor_blocking_threads_inc(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
130void rb_ractor_blocking_threads_dec(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
131
132void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r);
133void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
134void rb_ractor_terminate_all(void);
135bool rb_ractor_main_p_(void);
136void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
137void rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *th);
138VALUE rb_ractor_require(VALUE feature, bool silent);
139VALUE rb_ractor_autoload_load(VALUE space, ID id);
140
141VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
142
143RUBY_SYMBOL_EXPORT_BEGIN
144void rb_ractor_finish_marking(void);
145
146bool rb_ractor_shareable_p_continue(VALUE obj);
147
148// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
149// This function is for T_DATA::free_func
150void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key);
151
152RUBY_SYMBOL_EXPORT_END
153
154static inline bool
155rb_ractor_main_p(void)
156{
157 if (ruby_single_main_ractor) {
158 return true;
159 }
160 else {
161 return rb_ractor_main_p_();
162 }
163}
164
165static inline bool
166rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status)
167{
168 return r->status_ == status;
169}
170
171static inline void
172rb_ractor_sleeper_threads_inc(rb_ractor_t *r)
173{
174 r->threads.sleeper++;
175}
176
177static inline void
178rb_ractor_sleeper_threads_dec(rb_ractor_t *r)
179{
180 r->threads.sleeper--;
181}
182
183static inline void
184rb_ractor_sleeper_threads_clear(rb_ractor_t *r)
185{
186 r->threads.sleeper = 0;
187}
188
189static inline int
190rb_ractor_sleeper_thread_num(rb_ractor_t *r)
191{
192 return r->threads.sleeper;
193}
194
195static inline void
196rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th, bool always_reset)
197{
198 RUBY_DEBUG_LOG("th:%d->%u%s",
199 cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1,
200 rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : "");
201
202 if (cr->threads.running_ec != th->ec || always_reset) {
203 th->running_time_us = 0;
204 }
205
206 if (cr->threads.running_ec != th->ec) {
207 if (0) {
208 ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
209 (void *)cr->threads.running_ec, (void *)th->ec);
210 }
211 }
212 else {
213 return;
214 }
215
216 cr->threads.running_ec = th->ec;
217
218 VM_ASSERT(cr == GET_RACTOR());
219}
220
221#define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__)
222#ifdef RB_THREAD_LOCAL_SPECIFIER
223void rb_current_ec_set(rb_execution_context_t *ec);
224#endif
225
226static inline void
227rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
228{
229#ifdef RB_THREAD_LOCAL_SPECIFIER
230 rb_current_ec_set(ec);
231#else
232 native_tls_set(ruby_current_ec_key, ec);
233#endif
234 RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
235 VM_ASSERT(ec == NULL || cr->threads.running_ec != ec);
236 cr->threads.running_ec = ec;
237}
238
239void rb_vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
240void rb_vm_ractor_blocking_cnt_dec(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
241
242static inline uint32_t
243rb_ractor_id(const rb_ractor_t *r)
244{
245 return r->pub.id;
246}
247
248#if RACTOR_CHECK_MODE > 0
249# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
250
251uint32_t rb_ractor_current_id(void);
252
253static inline void
254rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
255{
256 RACTOR_BELONGING_ID(obj) = rid;
257}
258
259static inline uint32_t
260rb_ractor_belonging(VALUE obj)
261{
262 if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) {
263 return 0;
264 }
265 else {
266 return RACTOR_BELONGING_ID(obj);
267 }
268}
269
270extern bool rb_ractor_ignore_belonging_flag;
271
272static inline VALUE
273rb_ractor_confirm_belonging(VALUE obj)
274{
275 if (rb_ractor_ignore_belonging_flag) return obj;
276
277 uint32_t id = rb_ractor_belonging(obj);
278
279 if (id == 0) {
280 if (UNLIKELY(!rb_ractor_shareable_p(obj))) {
281 rp(obj);
282 rb_bug("id == 0 but not shareable");
283 }
284 }
285 else if (UNLIKELY(id != rb_ractor_current_id())) {
286 if (rb_ractor_shareable_p(obj)) {
287 // ok
288 }
289 else {
290 rp(obj);
291 rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id());
292 }
293 }
294 return obj;
295}
296
297static inline void
298rb_ractor_ignore_belonging(bool flag)
299{
300 rb_ractor_ignore_belonging_flag = flag;
301}
302
303#else
304#define rb_ractor_confirm_belonging(obj) obj
305#define rb_ractor_ignore_belonging(flag) (0)
306#endif
#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
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