summaryrefslogtreecommitdiff
path: root/ractor.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-10-31 00:40:04 +0900
committerKoichi Sasada <ko1@atdot.net>2020-10-31 01:48:00 +0900
commitfd089276999393a6f6bb2a0b614ac76ca6151ab2 (patch)
tree711b652e7051adc7ab23e150ce65cb0d8f4e2439 /ractor.c
parent66bf743b9309b479b6d5389e315ca54ea73aafae (diff)
Ractor's "will" doesn't need copying.
`r = Ractor.new{ expr }` generates the block return value from `expr` and we can get this value by `r.take`. Ractor.yield and Ractor#take passing values by copying on default. However, the block return value (we named it "will" in the code) is not referred from the Ractor because the Ractor is already dead. So we can pass the reference of "will" to another ractor without copying. We can apply same story for the propagated exception.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3724
Diffstat (limited to 'ractor.c')
-rw-r--r--ractor.c94
1 files changed, 63 insertions, 31 deletions
diff --git a/ractor.c b/ractor.c
index a89da04b33..203a4a88da 100644
--- a/ractor.c
+++ b/ractor.c
@@ -445,7 +445,7 @@ static void
ractor_move_setup(struct rb_ractor_basket *b, VALUE obj)
{
if (rb_ractor_shareable_p(obj)) {
- b->type = basket_type_shareable;
+ b->type = basket_type_ref;
b->v = obj;
}
else {
@@ -463,35 +463,41 @@ ractor_basket_clear(struct rb_ractor_basket *b)
b->sender = Qfalse;
}
+static void ractor_reset_belonging(VALUE obj); // in this file
+
static VALUE
ractor_basket_accept(struct rb_ractor_basket *b)
{
VALUE v;
switch (b->type) {
- case basket_type_shareable:
+ case basket_type_ref:
VM_ASSERT(rb_ractor_shareable_p(b->v));
v = b->v;
break;
- case basket_type_copy_marshal:
+ case basket_type_copy:
v = rb_marshal_load(b->v);
RB_GC_GUARD(b->v);
break;
- case basket_type_exception:
- {
- VALUE cause = rb_marshal_load(b->v);
- VALUE err = rb_exc_new_cstr(rb_eRactorRemoteError, "thrown by remote Ractor.");
- rb_ivar_set(err, rb_intern("@ractor"), b->sender);
- ractor_basket_clear(b);
- rb_ec_setup_exception(NULL, err, cause);
- rb_exc_raise(err);
- }
- // unreachable
case basket_type_move:
v = ractor_moved_setup(b->v);
break;
+ case basket_type_will:
+ v = b->v;
+ ractor_reset_belonging(v);
+ break;
default:
rb_bug("unreachable");
}
+
+ if (b->exception) {
+ VALUE cause = v;
+ VALUE err = rb_exc_new_cstr(rb_eRactorRemoteError, "thrown by remote Ractor.");
+ rb_ivar_set(err, rb_intern("@ractor"), b->sender);
+ ractor_basket_clear(b);
+ rb_ec_setup_exception(NULL, err, cause);
+ rb_exc_raise(err);
+ }
+
ractor_basket_clear(b);
return v;
}
@@ -500,18 +506,12 @@ static void
ractor_copy_setup(struct rb_ractor_basket *b, VALUE obj)
{
if (rb_ractor_shareable_p(obj)) {
- b->type = basket_type_shareable;
+ b->type = basket_type_ref;
b->v = obj;
}
else {
-#if 0
- // TODO: consider custom copy protocol
- switch (BUILTIN_TYPE(obj)) {
-
- }
-#endif
b->v = rb_marshal_dump(obj, Qnil);
- b->type = basket_type_copy_marshal;
+ b->type = basket_type_copy;
}
}
@@ -778,27 +778,29 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_
}
static void
-ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc)
+ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc, bool is_will)
{
basket->sender = rb_ec_ractor_ptr(ec)->self;
+ basket->exception = exc;
- if (!RTEST(move)) {
+ if (is_will) {
+ basket->type = basket_type_will;
+ basket->v = obj;
+ }
+ else if (!RTEST(move)) {
ractor_copy_setup(basket, obj);
}
else {
ractor_move_setup(basket, obj);
}
- if (exc) {
- basket->type = basket_type_exception;
- }
}
static VALUE
ractor_send(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
struct rb_ractor_basket basket;
- ractor_basket_setup(ec, &basket, obj, move, false);
+ ractor_basket_setup(ec, &basket, obj, move, false, false);
ractor_send_basket(ec, r, &basket);
return r->self;
}
@@ -942,7 +944,7 @@ ractor_select(rb_execution_context_t *ec, const VALUE *rs, int alen, VALUE yield
wait_status |= wait_yielding;
alen++;
- ractor_basket_setup(ec, &cr->wait.yielded_basket, yielded_value, move, false);
+ ractor_basket_setup(ec, &cr->wait.yielded_basket, yielded_value, move, false, false);
}
// TODO: shuffle actions
@@ -1400,7 +1402,7 @@ ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool e
ASSERT_ractor_unlocking(cr);
struct rb_ractor_basket basket;
- ractor_basket_setup(ec, &basket, v, Qfalse, exc);
+ ractor_basket_setup(ec, &basket, v, Qfalse, exc, true);
retry:
if (ractor_try_yield(ec, cr, &basket)) {
@@ -1921,7 +1923,7 @@ obj_hash_traverse_i(VALUE key, VALUE val, VALUE ptr)
}
static void
-obj_tdata_traverse_i(VALUE obj, void *ptr)
+obj_traverse_reachable_i(VALUE obj, void *ptr)
{
struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
@@ -2031,12 +2033,13 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
break;
case T_DATA:
+ case T_IMEMO:
{
struct obj_traverse_callback_data d = {
.stop = false,
.data = data,
};
- rb_objspace_reachable_objects_from(obj, obj_tdata_traverse_i, &d);
+ rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
if (d.stop) return 1;
}
break;
@@ -2180,4 +2183,33 @@ rb_ractor_shareable_p_continue(VALUE obj)
}
}
+#if RACTOR_CHECK_MODE > 0
+static enum obj_traverse_iterator_result
+reset_belonging_enter(VALUE obj)
+{
+ if (rb_ractor_shareable_p(obj)) {
+ return traverse_skip;
+ }
+ else {
+ rb_ractor_setup_belonging(obj);
+ return traverse_cont;
+ }
+}
+
+static enum obj_traverse_iterator_result
+null_leave(VALUE obj)
+{
+ return traverse_cont;
+}
+#endif
+
+static void
+ractor_reset_belonging(VALUE obj)
+{
+#if RACTOR_CHECK_MODE > 0
+ rb_obj_traverse(obj, reset_belonging_enter, null_leave);
+
+#endif
+}
+
#include "ractor.rbinc"