mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
66bf743b93
commit
fd08927699
Notes:
git
2020-10-31 01:48:37 +09:00
2 changed files with 67 additions and 35 deletions
94
ractor.c
94
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"
|
||||
|
|
8
ractor.h
8
ractor.h
|
@ -10,15 +10,15 @@
|
|||
|
||||
enum rb_ractor_basket_type {
|
||||
basket_type_none,
|
||||
basket_type_shareable,
|
||||
basket_type_copy_marshal,
|
||||
basket_type_copy_custom,
|
||||
basket_type_ref,
|
||||
basket_type_copy,
|
||||
basket_type_move,
|
||||
basket_type_exception,
|
||||
basket_type_will,
|
||||
};
|
||||
|
||||
struct rb_ractor_basket {
|
||||
enum rb_ractor_basket_type type;
|
||||
bool exception;
|
||||
VALUE v;
|
||||
VALUE sender;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue