Ruby  3.1.4p223 (2023-03-30 revision HEAD)
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 (0 || VM_CHECK_MODE || RUBY_DEBUG)
9 #endif
10 
11 enum 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 
44  // ractor lock
45  rb_nativethread_lock_t lock;
46 #if RACTOR_CHECK_MODE > 0
47  VALUE locked_by;
48 #endif
49  rb_nativethread_cond_t cond;
50 
51  // communication
52  struct rb_ractor_queue incoming_queue;
53  struct rb_ractor_waiting_list taking_ractors;
54 
55  bool incoming_port_closed;
56  bool outgoing_port_closed;
57 
58  struct ractor_wait {
59  enum ractor_wait_status {
60  wait_none = 0x00,
61  wait_receiving = 0x01,
62  wait_taking = 0x02,
63  wait_yielding = 0x04,
64  wait_moving = 0x08,
65  } status;
66 
67  enum ractor_wakeup_status {
68  wakeup_none,
69  wakeup_by_send,
70  wakeup_by_yield,
71  wakeup_by_take,
72  wakeup_by_close,
73  wakeup_by_interrupt,
74  wakeup_by_retry,
75  } wakeup_status;
76 
77  struct rb_ractor_basket yielded_basket;
78  struct rb_ractor_basket taken_basket;
79  } wait;
80 };
81 
83  struct rb_ractor_pub pub;
84 
85  struct rb_ractor_sync sync;
86  VALUE receiving_mutex;
87  bool yield_atexit;
88 
89  // vm wide barrier synchronization
90  rb_nativethread_cond_t barrier_wait_cond;
91 
92  // thread management
93  struct {
94  struct list_head set;
95  unsigned int cnt;
96  unsigned int blocking_cnt;
97  unsigned int sleeper;
99  rb_execution_context_t *running_ec;
100  rb_thread_t *main;
101  } threads;
102  VALUE thgroup_default;
103 
104  VALUE name;
105  VALUE loc;
106 
107  // created
108  // | ready to run
109  // ====================== inserted to vm->ractor
110  // v
111  // blocking <---+ all threads are blocking
112  // | |
113  // v |
114  // running -----+
115  // | all threads are terminated.
116  // ====================== removed from vm->ractor
117  // v
118  // terminated
119  //
120  // status is protected by VM lock (global state)
121 
122  enum ractor_status {
123  ractor_created,
124  ractor_running,
125  ractor_blocking,
126  ractor_terminated,
127  } status_;
128 
129  struct list_node vmlr_node;
130 
131  // ractor local data
132 
133  st_table *local_storage;
134  struct rb_id_table *idkey_local_storage;
135 
136  VALUE r_stdin;
137  VALUE r_stdout;
138  VALUE r_stderr;
139  VALUE verbose;
140  VALUE debug;
141 
142  rb_ractor_newobj_cache_t newobj_cache;
143 
144  // gc.c rb_objspace_reachable_objects_from
146  void *data;
147  void (*mark_func)(VALUE v, void *data);
148  } *mfd;
149 }; // rb_ractor_t is defined in vm_core.h
150 
151 
152 static inline VALUE
153 rb_ractor_self(const rb_ractor_t *r)
154 {
155  return r->pub.self;
156 }
157 
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);
165 
166 VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
167 
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);
172 
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
178 
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);
185 
186 VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
187 
188 RUBY_SYMBOL_EXPORT_BEGIN
189 bool rb_ractor_shareable_p_continue(VALUE obj);
190 
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);
194 
195 RUBY_SYMBOL_EXPORT_END
196 
197 static inline bool
198 rb_ractor_main_p(void)
199 {
200  if (ruby_single_main_ractor) {
201  return true;
202  }
203  else {
204  return rb_ractor_main_p_();
205  }
206 }
207 
208 static inline bool
209 rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status)
210 {
211  return r->status_ == status;
212 }
213 
214 static inline void
215 rb_ractor_sleeper_threads_inc(rb_ractor_t *r)
216 {
217  r->threads.sleeper++;
218 }
219 
220 static inline void
221 rb_ractor_sleeper_threads_dec(rb_ractor_t *r)
222 {
223  r->threads.sleeper--;
224 }
225 
226 static inline void
227 rb_ractor_sleeper_threads_clear(rb_ractor_t *r)
228 {
229  r->threads.sleeper = 0;
230 }
231 
232 static inline int
233 rb_ractor_sleeper_thread_num(rb_ractor_t *r)
234 {
235  return r->threads.sleeper;
236 }
237 
238 static inline void
239 rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
240 {
241  if (cr->threads.running_ec != th->ec) {
242  if (0) {
243  ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
244  (void *)cr->threads.running_ec, (void *)th->ec);
245  }
246  }
247  else {
248  return;
249  }
250 
251  if (cr->threads.running_ec != th->ec) {
252  th->running_time_us = 0;
253  }
254 
255  cr->threads.running_ec = th->ec;
256 
257  VM_ASSERT(cr == GET_RACTOR());
258 }
259 
260 static inline void
261 rb_ractor_set_current_ec(rb_ractor_t *cr, rb_execution_context_t *ec)
262 {
263 #ifdef RB_THREAD_LOCAL_SPECIFIER
264  #ifdef __APPLE__
265  rb_current_ec_set(ec);
266  #else
267  ruby_current_ec = ec;
268  #endif
269 #else
270  native_tls_set(ruby_current_ec_key, ec);
271 #endif
272 
273  if (cr->threads.running_ec != ec) {
274  if (0) {
275  ruby_debug_printf("rb_ractor_set_current_ec ec:%p->%p\n",
276  (void *)cr->threads.running_ec, (void *)ec);
277  }
278  }
279  else {
280  VM_ASSERT(0); // should be different
281  }
282 
283  cr->threads.running_ec = ec;
284 }
285 
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);
288 
289 static inline uint32_t
290 rb_ractor_id(const rb_ractor_t *r)
291 {
292  return r->pub.id;
293 }
294 
295 #if RACTOR_CHECK_MODE > 0
296 uint32_t rb_ractor_current_id(void);
297 
298 static inline void
299 rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
300 {
301  VALUE flags = RBASIC(obj)->flags & 0xffffffff; // 4B
302  RBASIC(obj)->flags = flags | ((VALUE)rid << 32);
303 }
304 
305 static inline void
306 rb_ractor_setup_belonging(VALUE obj)
307 {
308  rb_ractor_setup_belonging_to(obj, rb_ractor_current_id());
309 }
310 
311 static inline uint32_t
312 rb_ractor_belonging(VALUE obj)
313 {
314  if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) {
315  return 0;
316  }
317  else {
318  return RBASIC(obj)->flags >> 32;
319  }
320 }
321 
322 static inline VALUE
323 rb_ractor_confirm_belonging(VALUE obj)
324 {
325  uint32_t id = rb_ractor_belonging(obj);
326 
327  if (id == 0) {
328  if (UNLIKELY(!rb_ractor_shareable_p(obj))) {
329  rp(obj);
330  rb_bug("id == 0 but not shareable");
331  }
332  }
333  else if (UNLIKELY(id != rb_ractor_current_id())) {
334  if (rb_ractor_shareable_p(obj)) {
335  // ok
336  }
337  else {
338  rp(obj);
339  rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id());
340  }
341  }
342  return obj;
343 }
344 #else
345 #define rb_ractor_confirm_belonging(obj) obj
346 #endif
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:802
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
#define RBASIC(obj)
Convenient casting macro.
Definition: rbasic.h:40
Definition: st.h:79
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40