aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common.mk1
-rw-r--r--ractor.c39
-rw-r--r--transient_heap.c136
-rw-r--r--transient_heap.h4
4 files changed, 99 insertions, 81 deletions
diff --git a/common.mk b/common.mk
index b334056b4a..158828a11c 100644
--- a/common.mk
+++ b/common.mk
@@ -10384,6 +10384,7 @@ ractor.$(OBJEXT): {$(VPATH)}subst.h
ractor.$(OBJEXT): {$(VPATH)}thread.h
ractor.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
ractor.$(OBJEXT): {$(VPATH)}thread_native.h
+ractor.$(OBJEXT): {$(VPATH)}transient_heap.h
ractor.$(OBJEXT): {$(VPATH)}variable.h
ractor.$(OBJEXT): {$(VPATH)}vm_core.h
ractor.$(OBJEXT): {$(VPATH)}vm_debug.h
diff --git a/ractor.c b/ractor.c
index 1ed0272616..49a92a2661 100644
--- a/ractor.c
+++ b/ractor.c
@@ -14,6 +14,7 @@
#include "internal/struct.h"
#include "variable.h"
#include "gc.h"
+#include "transient_heap.h"
VALUE rb_cRactor;
static VALUE rb_eRactorError;
@@ -1127,16 +1128,33 @@ ractor_next_id(void)
}
static void
-vm_insert_ractor0(rb_vm_t *vm, rb_ractor_t *r)
+vm_insert_ractor0(rb_vm_t *vm, rb_ractor_t *r, bool single_ractor_mode)
{
RUBY_DEBUG_LOG("r:%u ractor.cnt:%u++", r->id, vm->ractor.cnt);
- VM_ASSERT(!rb_multi_ractor_p() || RB_VM_LOCKED_P());
+ VM_ASSERT(single_ractor_mode || RB_VM_LOCKED_P());
list_add_tail(&vm->ractor.set, &r->vmlr_node);
vm->ractor.cnt++;
}
static void
+cancel_single_ractor_mode(void)
+{
+ // enable multi-ractor mode
+ RUBY_DEBUG_LOG("enable multi-ractor mode", 0);
+
+ rb_gc_start();
+ rb_transient_heap_evacuate();
+
+ if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL)) {
+ rb_warn("Ractor is experimental, and the behavior may change in future versions of Ruby! "
+ "Also there are many implementation issues.");
+ }
+
+ ruby_single_main_ractor = NULL;
+}
+
+static void
vm_insert_ractor(rb_vm_t *vm, rb_ractor_t *r)
{
VM_ASSERT(ractor_status_p(r, ractor_created));
@@ -1144,29 +1162,22 @@ vm_insert_ractor(rb_vm_t *vm, rb_ractor_t *r)
if (rb_multi_ractor_p()) {
RB_VM_LOCK();
{
- vm_insert_ractor0(vm, r);
+ vm_insert_ractor0(vm, r, false);
vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
}
RB_VM_UNLOCK();
}
else {
- vm_insert_ractor0(vm, r);
-
- if (vm->ractor.cnt == 1) {
+ if (vm->ractor.cnt == 0) {
// main ractor
+ vm_insert_ractor0(vm, r, true);
ractor_status_set(r, ractor_blocking);
ractor_status_set(r, ractor_running);
}
else {
+ cancel_single_ractor_mode();
+ vm_insert_ractor0(vm, r, true);
vm_ractor_blocking_cnt_inc(vm, r, __FILE__, __LINE__);
-
- // enable multi-ractor mode
- RUBY_DEBUG_LOG("enable multi-ractor mode", 0);
- ruby_single_main_ractor = NULL;
-
- if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL)) {
- rb_warn("Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.");
- }
}
}
}
diff --git a/transient_heap.c b/transient_heap.c
index 357e4a4656..5b6fd89889 100644
--- a/transient_heap.c
+++ b/transient_heap.c
@@ -364,74 +364,72 @@ transient_heap_allocatable_header(struct transient_heap* theap, size_t size)
void *
rb_transient_heap_alloc(VALUE obj, size_t req_size)
{
- void *ret;
+ // only on single main ractor
+ if (ruby_single_main_ractor == NULL) return NULL;
- RB_VM_LOCK_ENTER();
- {
- struct transient_heap* theap = transient_heap_get();
- size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN);
+ void *ret;
+ struct transient_heap* theap = transient_heap_get();
+ size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN);
- TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) ||
- RB_TYPE_P(obj, T_OBJECT) ||
- RB_TYPE_P(obj, T_STRUCT) ||
- RB_TYPE_P(obj, T_HASH)); /* supported types */
+ TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) ||
+ RB_TYPE_P(obj, T_OBJECT) ||
+ RB_TYPE_P(obj, T_STRUCT) ||
+ RB_TYPE_P(obj, T_HASH)); /* supported types */
- if (size > TRANSIENT_HEAP_ALLOC_MAX) {
- if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj));
- ret = NULL;
- }
+ if (size > TRANSIENT_HEAP_ALLOC_MAX) {
+ if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj));
+ ret = NULL;
+ }
#if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE == 0
- else if (RB_OBJ_PROMOTED_RAW(obj)) {
- if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [promoted object] %s\n", rb_obj_info(obj));
- ret = NULL;
- }
+ else if (RB_OBJ_PROMOTED_RAW(obj)) {
+ if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [promoted object] %s\n", rb_obj_info(obj));
+ ret = NULL;
+ }
#else
- else if (RBASIC_CLASS(obj) == 0) {
- if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [hidden object] %s\n", rb_obj_info(obj));
- ret = NULL;
- }
+ else if (RBASIC_CLASS(obj) == 0) {
+ if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [hidden object] %s\n", rb_obj_info(obj));
+ ret = NULL;
+ }
#endif
- else {
- struct transient_alloc_header *header = transient_heap_allocatable_header(theap, size);
- if (header) {
- void *ptr;
+ else {
+ struct transient_alloc_header *header = transient_heap_allocatable_header(theap, size);
+ if (header) {
+ void *ptr;
- /* header is poisoned to prevent buffer overflow, should
- * unpoison first... */
- asan_unpoison_memory_region(header, sizeof *header, true);
+ /* header is poisoned to prevent buffer overflow, should
+ * unpoison first... */
+ asan_unpoison_memory_region(header, sizeof *header, true);
- header->size = size;
- header->magic = TRANSIENT_HEAP_ALLOC_MAGIC;
- header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE;
- header->obj = obj; /* TODO: can we eliminate it? */
+ header->size = size;
+ header->magic = TRANSIENT_HEAP_ALLOC_MAGIC;
+ header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE;
+ header->obj = obj; /* TODO: can we eliminate it? */
- /* header is fixed; shall poison again */
- asan_poison_memory_region(header, sizeof *header);
- ptr = header + 1;
+ /* header is fixed; shall poison again */
+ asan_poison_memory_region(header, sizeof *header);
+ ptr = header + 1;
- theap->total_objects++; /* statistics */
+ theap->total_objects++; /* statistics */
#if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE
- if (RB_OBJ_PROMOTED_RAW(obj)) {
- transient_heap_promote_add(theap, obj);
- }
+ if (RB_OBJ_PROMOTED_RAW(obj)) {
+ transient_heap_promote_add(theap, obj);
+ }
#endif
- if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: header:%p ptr:%p size:%d obj:%s\n", (void *)header, ptr, (int)size, rb_obj_info(obj));
+ if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: header:%p ptr:%p size:%d obj:%s\n", (void *)header, ptr, (int)size, rb_obj_info(obj));
- RB_DEBUG_COUNTER_INC(theap_alloc);
+ RB_DEBUG_COUNTER_INC(theap_alloc);
- /* ptr is set up; OK to unpoison. */
- asan_unpoison_memory_region(ptr, size - sizeof *header, true);
- ret = ptr;
- }
- else {
- if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [no enough space: %ld] %s\n", (long)size, rb_obj_info(obj));
- RB_DEBUG_COUNTER_INC(theap_alloc_fail);
- ret = NULL;
- }
+ /* ptr is set up; OK to unpoison. */
+ asan_unpoison_memory_region(ptr, size - sizeof *header, true);
+ ret = ptr;
+ }
+ else {
+ if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [no enough space: %ld] %s\n", (long)size, rb_obj_info(obj));
+ RB_DEBUG_COUNTER_INC(theap_alloc_fail);
+ ret = NULL;
}
}
- RB_VM_LOCK_LEAVE();
return ret;
}
@@ -775,16 +773,16 @@ transient_heap_update_status(struct transient_heap* theap, enum transient_heap_s
static void
transient_heap_evacuate(void *dmy)
{
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
- {
- struct transient_heap* theap = transient_heap_get();
+ struct transient_heap* theap = transient_heap_get();
- if (theap->status == transient_heap_marking) {
- if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_evacuate: skip while transient_heap_marking\n");
- }
- else {
- VALUE gc_disabled = rb_gc_disable_no_rest();
+ if (theap->total_marked_objects == 0) return;
+ if (ruby_single_main_ractor == NULL) rb_bug("not single ractor mode");
+ if (theap->status == transient_heap_marking) {
+ if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_evacuate: skip while transient_heap_marking\n");
+ }
+ else {
+ VALUE gc_disabled = rb_gc_disable_no_rest();
+ {
struct transient_heap_block* block;
RUBY_DEBUG_LOG("start gc_disabled:%d", RTEST(gc_disabled));
@@ -825,12 +823,16 @@ transient_heap_evacuate(void *dmy)
transient_heap_verify(theap);
transient_heap_update_status(theap, transient_heap_none);
-
- if (gc_disabled != Qtrue) rb_gc_enable();
- RUBY_DEBUG_LOG("finish", 0);
}
+ if (gc_disabled != Qtrue) rb_gc_enable();
+ RUBY_DEBUG_LOG("finish", 0);
}
- RB_VM_LOCK_LEAVE();
+}
+
+void
+rb_transient_heap_evacuate(void)
+{
+ transient_heap_evacuate(NULL);
}
static void
@@ -964,9 +966,9 @@ rb_transient_heap_finish_marking(void)
struct transient_heap* theap = transient_heap_get();
- if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! rb_transient_heap_finish_marking objects:%d, marked:%d\n",
- theap->total_objects,
- theap->total_marked_objects);
+ RUBY_DEBUG_LOG("objects:%d, marked:%d",
+ theap->total_objects,
+ theap->total_marked_objects);
if (TRANSIENT_HEAP_DEBUG >= 2) transient_heap_dump(theap);
TH_ASSERT(theap->total_objects >= theap->total_marked_objects);
diff --git a/transient_heap.h b/transient_heap.h
index 363e7a2da2..4ac52aad07 100644
--- a/transient_heap.h
+++ b/transient_heap.h
@@ -31,6 +31,9 @@ void rb_transient_heap_start_marking(int full_marking);
void rb_transient_heap_finish_marking(void);
void rb_transient_heap_update_references(void);
+/* used by ractor.c */
+void rb_transient_heap_evacuate(void);
+
/* for debug API */
void rb_transient_heap_dump(void);
void rb_transient_heap_verify(void);
@@ -49,6 +52,7 @@ void rb_struct_transient_heap_evacuate(VALUE st, int promote);
#define rb_transient_heap_promote(obj) ((void)0)
#define rb_transient_heap_start_marking(full_marking) ((void)0)
#define rb_transient_heap_update_references() ((void)0)
+#define rb_transient_heap_evacuate() ((void)0)
#define rb_transient_heap_finish_marking() ((void)0)
#define rb_transient_heap_mark(obj, ptr) ((void)0)