Ruby 3.2.1p31 (2023-02-08 revision 31819e82c88c6f8ecfaeb162519bfa26a14b21fd)
ractor_core.h
1#include "ruby/ruby.h"
2#include "ruby/ractor.h"
3#include "vm_core.h"
4#include "id_table.h"
5#include "vm_debug.h"
6
7#ifndef RACTOR_CHECK_MODE
8#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
9#endif
10
11enum rb_ractor_basket_type {
12 basket_type_none,
13 basket_type_ref,
14 basket_type_copy,
15 basket_type_move,
16 basket_type_will,
17 basket_type_deleted,
18 basket_type_reserved,
19};
20
22 bool exception;
23 enum rb_ractor_basket_type type;
24 VALUE v;
25 VALUE sender;
26};
27
29 struct rb_ractor_basket *baskets;
30 int start;
31 int cnt;
32 int size;
33 unsigned int serial;
34 unsigned int reserved_cnt;
35};
36
38 int cnt;
39 int size;
40 rb_ractor_t **ractors;
41};
42
43enum rb_ractor_wait_status {
44 wait_none = 0x00,
45 wait_receiving = 0x01,
46 wait_taking = 0x02,
47 wait_yielding = 0x04,
48 wait_moving = 0x08,
49};
50
51enum rb_ractor_wakeup_status {
52 wakeup_none,
53 wakeup_by_send,
54 wakeup_by_yield,
55 wakeup_by_take,
56 wakeup_by_close,
57 wakeup_by_interrupt,
58 wakeup_by_retry,
59};
60
62 // ractor lock
64#if RACTOR_CHECK_MODE > 0
65 VALUE locked_by;
66#endif
68
69 // communication
70 struct rb_ractor_queue incoming_queue;
71 struct rb_ractor_waiting_list taking_ractors;
72
73 bool incoming_port_closed;
74 bool outgoing_port_closed;
75
76 struct ractor_wait {
77 enum rb_ractor_wait_status status;
78 enum rb_ractor_wakeup_status wakeup_status;
79 struct rb_ractor_basket yielded_basket;
80 struct rb_ractor_basket taken_basket;
81 } wait;
82};
83
84// created
85// | ready to run
86// ====================== inserted to vm->ractor
87// v
88// blocking <---+ all threads are blocking
89// | |
90// v |
91// running -----+
92// | all threads are terminated.
93// ====================== removed from vm->ractor
94// v
95// terminated
96//
97// status is protected by VM lock (global state)
98enum ractor_status {
99 ractor_created,
100 ractor_running,
101 ractor_blocking,
102 ractor_terminated,
103};
104
106 struct rb_ractor_pub pub;
107
108 struct rb_ractor_sync sync;
109 VALUE receiving_mutex;
110 bool yield_atexit;
111
112 // vm wide barrier synchronization
113 rb_nativethread_cond_t barrier_wait_cond;
114
115 // thread management
116 struct {
117 struct ccan_list_head set;
118 unsigned int cnt;
119 unsigned int blocking_cnt;
120 unsigned int sleeper;
121 struct rb_thread_sched sched;
122 rb_execution_context_t *running_ec;
123 rb_thread_t *main;
124 } threads;
125 VALUE thgroup_default;
126
127 VALUE name;
128 VALUE loc;
129
130 enum ractor_status status_;
131
132 struct ccan_list_node vmlr_node;
133
134 // ractor local data
135
136 st_table *local_storage;
137 struct rb_id_table *idkey_local_storage;
138
139 VALUE r_stdin;
140 VALUE r_stdout;
141 VALUE r_stderr;
142 VALUE verbose;
143 VALUE debug;
144
145 rb_ractor_newobj_cache_t newobj_cache;
146
147 // gc.c rb_objspace_reachable_objects_from
149 void *data;
150 void (*mark_func)(VALUE v, void *data);
151 } *mfd;
152}; // rb_ractor_t is defined in vm_core.h
153
154
155static inline VALUE
156rb_ractor_self(const rb_ractor_t *r)
157{
158 return r->pub.self;
159}
160
161rb_ractor_t *rb_ractor_main_alloc(void);
162void rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *main_ractor, rb_thread_t *main_thread);
163void rb_ractor_atexit(rb_execution_context_t *ec, VALUE result);
164void rb_ractor_atexit_exception(rb_execution_context_t *ec);
165void rb_ractor_teardown(rb_execution_context_t *ec);
166void rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *g, int len, VALUE *ptr);
167void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE args);
168
169VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
170
171int rb_ractor_living_thread_num(const rb_ractor_t *);
172VALUE rb_ractor_thread_list(rb_ractor_t *r);
173bool rb_ractor_p(VALUE rv);
174
175void rb_ractor_living_threads_init(rb_ractor_t *r);
176void rb_ractor_living_threads_insert(rb_ractor_t *r, rb_thread_t *th);
177void rb_ractor_living_threads_remove(rb_ractor_t *r, rb_thread_t *th);
178void rb_ractor_blocking_threads_inc(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
179void rb_ractor_blocking_threads_dec(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
180
181void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r);
182void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
183void rb_ractor_terminate_all(void);
184bool rb_ractor_main_p_(void);
185void rb_ractor_finish_marking(void);
186void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
187
188VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
189
190RUBY_SYMBOL_EXPORT_BEGIN
191bool rb_ractor_shareable_p_continue(VALUE obj);
192
193// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
194// This function is for T_DATA::free_func
195void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key);
196
197RUBY_SYMBOL_EXPORT_END
198
199static inline bool
200rb_ractor_main_p(void)
201{
202 if (ruby_single_main_ractor) {
203 return true;
204 }
205 else {
206 return rb_ractor_main_p_();
207 }
208}
209
210static inline bool
211rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status)
212{
213 return r->status_ == status;
214}
215
216static inline void
217rb_ractor_sleeper_threads_inc(rb_ractor_t *r)
218{
219 r->threads.sleeper++;
220}
221
222static inline void
223rb_ractor_sleeper_threads_dec(rb_ractor_t *r)
224{
225 r->threads.sleeper--;
226}
227
228static inline void
229rb_ractor_sleeper_threads_clear(rb_ractor_t *r)
230{
231 r->threads.sleeper = 0;
232}
233
234static inline int
235rb_ractor_sleeper_thread_num(rb_ractor_t *r)
236{
237 return r->threads.sleeper;
238}
239
240static inline void
241rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
242{
243 if (cr->threads.running_ec != th->ec) {
244 if (0) {
245 ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
246 (void *)cr->threads.running_ec, (void *)th->ec);
247 }
248 }
249 else {
250 return;
251 }
252
253 if (cr->threads.running_ec != th->ec) {
254 th->running_time_us = 0;
255 }
256
257 cr->threads.running_ec = th->ec;
258
259 VM_ASSERT(cr == GET_RACTOR());
260}
261
262#define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__)
263
264static inline void
265rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
266{
267#ifdef RB_THREAD_LOCAL_SPECIFIER
268 #ifdef __APPLE__
269 rb_current_ec_set(ec);
270 #else
271 ruby_current_ec = ec;
272 #endif
273#else
274 native_tls_set(ruby_current_ec_key, ec);
275#endif
276 RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
277 VM_ASSERT(cr->threads.running_ec != ec);
278 cr->threads.running_ec = ec;
279}
280
281void rb_vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
282void rb_vm_ractor_blocking_cnt_dec(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
283
284static inline uint32_t
285rb_ractor_id(const rb_ractor_t *r)
286{
287 return r->pub.id;
288}
289
290#if RACTOR_CHECK_MODE > 0
291# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
292
293uint32_t rb_ractor_current_id(void);
294
295static inline void
296rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
297{
298 RACTOR_BELONGING_ID(obj) = rid;
299}
300
301static inline void
302rb_ractor_setup_belonging(VALUE obj)
303{
304 rb_ractor_setup_belonging_to(obj, rb_ractor_current_id());
305}
306
307static inline uint32_t
308rb_ractor_belonging(VALUE obj)
309{
310 if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) {
311 return 0;
312 }
313 else {
314 return RACTOR_BELONGING_ID(obj);
315 }
316}
317
318static inline VALUE
319rb_ractor_confirm_belonging(VALUE obj)
320{
321 uint32_t id = rb_ractor_belonging(obj);
322
323 if (id == 0) {
324 if (UNLIKELY(!rb_ractor_shareable_p(obj))) {
325 rp(obj);
326 rb_bug("id == 0 but not shareable");
327 }
328 }
329 else if (UNLIKELY(id != rb_ractor_current_id())) {
330 if (rb_ractor_shareable_p(obj)) {
331 // ok
332 }
333 else {
334 rp(obj);
335 rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id());
336 }
337 }
338 return obj;
339}
340#else
341#define rb_ractor_confirm_belonging(obj) obj
342#endif
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:794
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 VALUE
Type that represents a Ruby object.
Definition: value.h:40