summaryrefslogtreecommitdiff
path: root/ractor_core.h
diff options
context:
space:
mode:
Diffstat (limited to 'ractor_core.h')
-rw-r--r--ractor_core.h345
1 files changed, 345 insertions, 0 deletions
diff --git a/ractor_core.h b/ractor_core.h
new file mode 100644
index 0000000000..c692ebbbbf
--- /dev/null
+++ b/ractor_core.h
@@ -0,0 +1,345 @@
+#include "internal/gc.h"
+#include "ruby/ruby.h"
+#include "ruby/ractor.h"
+#include "vm_core.h"
+#include "id_table.h"
+#include "vm_debug.h"
+
+#ifndef RACTOR_CHECK_MODE
+#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
+#endif
+
+// experimental flag because it is not sure it is the common pattern
+#define RUBY_TYPED_FROZEN_SHAREABLE_NO_REC RUBY_FL_FINALIZE
+
+struct rb_ractor_sync {
+ // ractor lock
+ rb_nativethread_lock_t lock;
+
+#if RACTOR_CHECK_MODE > 0
+ VALUE locked_by;
+#endif
+
+#ifndef RUBY_THREAD_PTHREAD_H
+ rb_nativethread_cond_t wakeup_cond;
+#endif
+
+ // incoming messages
+ struct ractor_queue *recv_queue;
+
+ // waiting threads for receiving
+ struct ccan_list_head waiters;
+
+ // ports
+ VALUE default_port_value;
+ struct st_table *ports;
+ size_t next_port_id;
+
+ // monitors
+ struct ccan_list_head monitors;
+
+ // value
+ rb_ractor_t *successor;
+ VALUE legacy;
+ bool legacy_exc;
+};
+
+// created
+// | ready to run
+// ====================== inserted to vm->ractor
+// v
+// blocking <---+ all threads are blocking
+// | |
+// v |
+// running -----+
+// | all threads are terminated.
+// ====================== removed from vm->ractor
+// v
+// terminated
+//
+// status is protected by VM lock (global state)
+enum ractor_status {
+ ractor_created,
+ ractor_running,
+ ractor_blocking,
+ ractor_terminated,
+};
+
+struct rb_ractor_struct {
+ struct rb_ractor_pub pub;
+ struct rb_ractor_sync sync;
+
+ // thread management
+ struct {
+ struct ccan_list_head set;
+ unsigned int cnt;
+ unsigned int blocking_cnt;
+ unsigned int sleeper;
+ struct rb_thread_sched sched;
+ rb_execution_context_t *running_ec;
+ rb_thread_t *main;
+ } threads;
+
+ VALUE thgroup_default;
+
+ VALUE name;
+ VALUE loc;
+
+ enum ractor_status status_;
+
+ struct ccan_list_node vmlr_node;
+
+ // ractor local data
+
+ rb_serial_t next_ec_serial;
+
+ st_table *local_storage;
+ struct rb_id_table *idkey_local_storage;
+ VALUE local_storage_store_lock;
+
+ VALUE r_stdin;
+ VALUE r_stdout;
+ VALUE r_stderr;
+ VALUE verbose;
+ VALUE debug;
+
+ bool malloc_gc_disabled;
+ bool main_ractor;
+ void *newobj_cache;
+}; // rb_ractor_t is defined in vm_core.h
+
+enum ractor_wakeup_status {
+ wakeup_none,
+ wakeup_by_send,
+ wakeup_by_interrupt,
+ // wakeup_by_close,
+};
+
+struct ractor_waiter {
+ enum ractor_wakeup_status wakeup_status;
+ rb_thread_t *th;
+ struct ccan_list_node node;
+ rb_atomic_t event_serial;
+};
+
+static inline VALUE
+rb_ractor_self(const rb_ractor_t *r)
+{
+ return r->pub.self;
+}
+
+rb_ractor_t *rb_ractor_main_alloc(void);
+void rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *main_ractor, rb_thread_t *main_thread);
+void rb_ractor_atexit(rb_execution_context_t *ec, VALUE result);
+void rb_ractor_atexit_exception(rb_execution_context_t *ec);
+void rb_ractor_teardown(rb_execution_context_t *ec);
+void rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *g, int len, VALUE *ptr);
+void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE args);
+
+VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
+
+int rb_ractor_living_thread_num(const rb_ractor_t *);
+VALUE rb_ractor_thread_list(void);
+bool rb_ractor_p(VALUE rv);
+
+void rb_ractor_living_threads_init(rb_ractor_t *r);
+void rb_ractor_living_threads_insert(rb_ractor_t *r, rb_thread_t *th);
+void rb_ractor_living_threads_remove(rb_ractor_t *r, rb_thread_t *th);
+void rb_ractor_blocking_threads_inc(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
+void rb_ractor_blocking_threads_dec(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG
+
+void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r);
+void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
+void rb_ractor_terminate_all(void);
+bool rb_ractor_main_p_(void);
+void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
+void rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *th);
+VALUE rb_ractor_require(VALUE feature, bool silent);
+VALUE rb_ractor_autoload_load(VALUE space, ID id);
+
+VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
+st_table *rb_ractor_targeted_hooks(rb_ractor_t *cr);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+void rb_ractor_finish_marking(void);
+
+bool rb_ractor_shareable_p_continue(VALUE obj);
+
+// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
+// This function is for T_DATA::free_func
+void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key);
+
+RUBY_SYMBOL_EXPORT_END
+
+static inline bool
+rb_ractor_main_p(void)
+{
+ if (ruby_single_main_ractor) {
+ return true;
+ }
+ else {
+ return rb_ractor_main_p_();
+ }
+}
+
+static inline bool
+rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status)
+{
+ return r->status_ == status;
+}
+
+static inline void
+rb_ractor_sleeper_threads_inc(rb_ractor_t *r)
+{
+ r->threads.sleeper++;
+}
+
+static inline void
+rb_ractor_sleeper_threads_dec(rb_ractor_t *r)
+{
+ r->threads.sleeper--;
+}
+
+static inline void
+rb_ractor_sleeper_threads_clear(rb_ractor_t *r)
+{
+ r->threads.sleeper = 0;
+}
+
+static inline int
+rb_ractor_sleeper_thread_num(rb_ractor_t *r)
+{
+ return r->threads.sleeper;
+}
+
+static inline void
+rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th, bool always_reset)
+{
+ RUBY_DEBUG_LOG("th:%d->%u%s",
+ cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1,
+ rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : "");
+
+ if (cr->threads.running_ec != th->ec || always_reset) {
+ th->running_time_us = 0;
+ }
+
+ if (cr->threads.running_ec != th->ec) {
+ if (0) {
+ ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
+ (void *)cr->threads.running_ec, (void *)th->ec);
+ }
+ }
+ else {
+ return;
+ }
+
+ cr->threads.running_ec = th->ec;
+
+ VM_ASSERT(cr == GET_RACTOR());
+}
+
+#define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__)
+#ifdef RB_THREAD_LOCAL_SPECIFIER
+void rb_current_ec_set(rb_execution_context_t *ec);
+#endif
+
+static inline void
+rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
+{
+#ifdef RB_THREAD_LOCAL_SPECIFIER
+ rb_current_ec_set(ec);
+#else
+ native_tls_set(ruby_current_ec_key, ec);
+#endif
+ RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
+ VM_ASSERT(ec == NULL || cr->threads.running_ec != ec);
+ cr->threads.running_ec = ec;
+}
+
+void rb_vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
+void rb_vm_ractor_blocking_cnt_dec(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line);
+
+static inline uint32_t
+rb_ractor_id(const rb_ractor_t *r)
+{
+ return r->pub.id;
+}
+
+static inline void
+rb_ractor_targeted_hooks_incr(rb_ractor_t *cr)
+{
+ cr->pub.targeted_hooks_cnt++;
+}
+
+static inline void
+rb_ractor_targeted_hooks_decr(rb_ractor_t *cr)
+{
+ RUBY_ASSERT(cr->pub.targeted_hooks_cnt > 0);
+ cr->pub.targeted_hooks_cnt--;
+}
+
+static inline unsigned int
+rb_ractor_targeted_hooks_cnt(rb_ractor_t *cr)
+{
+ return cr->pub.targeted_hooks_cnt;
+}
+
+#if RACTOR_CHECK_MODE > 0
+# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
+
+uint32_t rb_ractor_current_id(void);
+
+static inline void
+rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
+{
+ RACTOR_BELONGING_ID(obj) = rid;
+}
+
+static inline uint32_t
+rb_ractor_belonging(VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) {
+ return 0;
+ }
+ else {
+ return RACTOR_BELONGING_ID(obj);
+ }
+}
+
+extern bool rb_ractor_ignore_belonging_flag;
+
+static inline VALUE
+rb_ractor_confirm_belonging(VALUE obj)
+{
+ if (rb_ractor_ignore_belonging_flag) return obj;
+
+ uint32_t id = rb_ractor_belonging(obj);
+
+ if (id == 0) {
+ if (UNLIKELY(!rb_ractor_shareable_p(obj))) {
+ rp(obj);
+ rb_bug("id == 0 but not shareable");
+ }
+ }
+ else if (UNLIKELY(id != rb_ractor_current_id())) {
+ if (rb_ractor_shareable_p(obj)) {
+ // ok
+ }
+ else {
+ rp(obj);
+ rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id());
+ }
+ }
+ return obj;
+}
+
+static inline void
+rb_ractor_ignore_belonging(bool flag)
+{
+ rb_ractor_ignore_belonging_flag = flag;
+}
+
+#else
+#define rb_ractor_confirm_belonging(obj) obj
+#define rb_ractor_ignore_belonging(flag) (0)
+#endif