14static VALUE rb_cRactorPort;
20static void ractor_add_port(
rb_ractor_t *r, st_data_t
id);
28ractor_port_mark(
void *ptr)
33 rb_gc_mark(rp->r->pub.self);
45 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
52 return cr->sync.next_port_id++;
56RACTOR_PORT_PTR(
VALUE self)
58 VM_ASSERT(rb_typeddata_is_kind_of(self, &ractor_port_data_type));
59 return RTYPEDDATA_GET_DATA(self);
64ractor_port_ptr_check(
VALUE self)
68 if (UNLIKELY(rp->r == NULL)) {
76ractor_port_alloc(
VALUE klass)
91 rp->id_ = ractor_genid_for_port(r);
93 ractor_add_port(r, ractor_port_id(rp));
107ractor_port_initialize(
VALUE self)
109 return ractor_port_init(self, GET_RACTOR());
114ractor_port_initialize_copy(
VALUE self,
VALUE orig)
117 struct ractor_port *src = ractor_port_ptr_check(orig);
120 dst->id_ = ractor_port_id(src);
128 VALUE rpv = ractor_port_alloc(rb_cRactorPort);
129 ractor_port_init(rpv, r);
134ractor_port_p(
VALUE self)
136 return rb_typeddata_is_kind_of(self, &ractor_port_data_type);
142 const struct ractor_port *rp = ractor_port_ptr_check(self);
144 if (rp->r != rb_ec_ractor_ptr(ec)) {
145 rb_raise(rb_eRactorError,
"only allowed from the creator Ractor of this port");
148 VALUE v = ractor_receive(ec, rp);
156 const struct ractor_port *rp = ractor_port_ptr_check(self);
157 ractor_send(ec, rp, obj,
RTEST(move));
168 const struct ractor_port *rp = ractor_port_ptr_check(self);
172 if (rb_ec_ractor_ptr(ec) == r) {
175 closed = ractor_closed_port_p(ec, r, rp);
184 closed = ractor_closed_port_p(ec, r, rp);
195 const struct ractor_port *rp = ractor_port_ptr_check(self);
199 rb_raise(rb_eRactorError,
"closing port by other ractors is not allowed");
202 ractor_close_port(ec, cr, rp);
210enum ractor_basket_type {
221 enum ractor_basket_type type;
242 struct ccan_list_node node;
247ractor_basket_type_p(
const struct ractor_basket *b,
enum ractor_basket_type type)
249 return b->type == type;
255 return ractor_basket_type_p(b, basket_type_none);
265 if (b->type != basket_type_move) {
276 if (cr != NULL && cr->sending_basket == b) {
277 cr->sending_basket = NULL;
282 if (b->type == basket_type_move && b->p.move_courier) {
284 rb_ractor_move_courier_free(b->p.move_courier);
285 b->p.move_courier = NULL;
291ractor_basket_alloc(
void)
300 struct ccan_list_head set;
307 ccan_list_head_init(&rq->set);
312ractor_queue_new(
void)
315 ractor_queue_init(rq);
324 ccan_list_for_each(&rq->set, b, node) {
325 ractor_basket_mark(b);
334 ccan_list_for_each_safe(&rq->set, b, nxt, node) {
335 ccan_list_del_init(&b->node);
336 ractor_basket_free(b);
339 VM_ASSERT(ccan_list_empty(&rq->set));
351 ccan_list_for_each(&rq->set, b, node) {
366 struct ccan_list_head *src = &src_rq->set;
367 struct ccan_list_head *dst = &dst_rq->set;
369 dst->n.next = src->n.next;
370 dst->n.prev = src->n.prev;
371 dst->n.next->prev = &dst->n;
372 dst->n.prev->next = &dst->n;
373 ccan_list_head_init(src);
387 return ccan_list_empty(&rq->set);
393 VM_ASSERT(GET_RACTOR() == r);
401 ccan_list_add_tail(&rq->set, &basket->node);
410 ccan_list_for_each(&rq->set, b, node) {
411 fprintf(stderr,
"%d type:%s %p\n", i, basket_type_name(b->type), (
void *)b);
417static void ractor_delete_port(
rb_ractor_t *cr, st_data_t
id,
bool locked);
420ractor_get_queue(
rb_ractor_t *cr, st_data_t
id,
bool locked)
422 VM_ASSERT(cr == GET_RACTOR());
426 if (cr->sync.ports && st_lookup(cr->sync.ports,
id, (st_data_t *)&rq)) {
427 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
428 ractor_delete_port(cr,
id, locked);
446 ASSERT_ractor_unlocking(r);
448 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
452 st_table *
const old_tab = r->sync.ports;
457 inserted = st_insert_no_rebuild(old_tab,
id, (st_data_t)rq) >= 0;
465 st_table *
const new_tab = st_copy(old_tab);
466 st_insert(new_tab,
id, (st_data_t)rq);
470 VM_ASSERT(r->sync.ports == old_tab);
471 r->sync.ports = new_tab;
475 st_free_table(old_tab);
480ractor_delete_port_locked(
rb_ractor_t *cr, st_data_t
id)
482 ASSERT_ractor_locking(cr);
484 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
488 if (st_delete(cr->sync.ports, &
id, (st_data_t *)&rq)) {
489 ractor_queue_free(rq);
497ractor_delete_port(
rb_ractor_t *cr, st_data_t
id,
bool locked)
500 ractor_delete_port_locked(cr,
id);
503 RACTOR_LOCK_SELF(cr);
505 ractor_delete_port_locked(cr,
id);
507 RACTOR_UNLOCK_SELF(cr);
514 return RACTOR_PORT_PTR(r->sync.default_port_value);
520 return r->sync.default_port_value;
526 VM_ASSERT(rb_ec_ractor_ptr(ec) == rp->r ? 1 : (ASSERT_ractor_locking(rp->r), 1));
530 if (rp->r->sync.ports && st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
544 VM_ASSERT(cr == rp->r);
547 RACTOR_LOCK_SELF(cr);
549 ractor_deliver_incoming_messages(ec, cr);
551 if (st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
552 ractor_queue_close(rq);
554 if (ractor_queue_empty_p(cr, rq)) {
556 ractor_delete_port(cr, ractor_port_id(rp),
true);
562 RACTOR_UNLOCK_SELF(cr);
568ractor_free_all_ports_i(st_data_t port_id, st_data_t val, st_data_t dat)
573 ractor_queue_free(rq);
580 if (cr->sync.ports) {
581 st_foreach(cr->sync.ports, ractor_free_all_ports_i, (st_data_t)cr);
582 st_free_table(cr->sync.ports);
583 cr->sync.ports = NULL;
586 if (cr->sync.recv_queue) {
587 ractor_queue_free(cr->sync.recv_queue);
588 cr->sync.recv_queue = NULL;
592#if defined(HAVE_WORKING_FORK)
596 ractor_free_all_ports(r);
597 r->sync.legacy =
Qnil;
605 struct ccan_list_node node;
615 ccan_list_for_each(&r->sync.monitors, rm, node) {
616 rb_gc_mark(rm->port.r->pub.self);
621ractor_exit_token(
bool exc)
624 RUBY_DEBUG_LOG(
"aborted");
628 RUBY_DEBUG_LOG(
"exited");
637 bool terminated =
false;
638 const struct ractor_port *rp = ractor_port_ptr_check(port);
644 if (UNDEF_P(r->sync.legacy)) {
645 RUBY_DEBUG_LOG(
"OK/r:%u -> port:%u@r%u", (
unsigned int)rb_ractor_id(r), (
unsigned int)ractor_port_id(&rm->port), (
unsigned int)rb_ractor_id(rm->port.r));
646 ccan_list_add_tail(&r->sync.monitors, &rm->node);
649 RUBY_DEBUG_LOG(
"NG/r:%u -> port:%u@r%u", (
unsigned int)rb_ractor_id(r), (
unsigned int)ractor_port_id(&rm->port), (
unsigned int)rb_ractor_id(rm->port.r));
657 ractor_port_send(ec, port, ractor_exit_token(r->sync.legacy_exc),
Qfalse);
670 const struct ractor_port *rp = ractor_port_ptr_check(port);
674 if (UNDEF_P(r->sync.legacy)) {
677 ccan_list_for_each_safe(&r->sync.monitors, rm, nxt, node) {
678 if (rm->port.r == rp->r && ractor_port_id(&rm->port) == ractor_port_id(rp)) {
679 RUBY_DEBUG_LOG(
"r:%u -> port:%u@r%u",
680 (
unsigned int)rb_ractor_id(r),
681 (
unsigned int)ractor_port_id(&rm->port),
682 (
unsigned int)rb_ractor_id(rm->port.r));
683 ccan_list_del(&rm->node);
697 RUBY_DEBUG_LOG(
"exc:%d", exc);
698 VM_ASSERT(!UNDEF_P(legacy));
699 VM_ASSERT(cr->sync.legacy ==
Qundef);
701 RACTOR_LOCK_SELF(cr);
703 ractor_free_all_ports(cr);
705 cr->sync.legacy = legacy;
706 cr->sync.legacy_exc = exc;
708 RACTOR_UNLOCK_SELF(cr);
717 VALUE token = ractor_exit_token(cr->sync.legacy_exc);
720 ccan_list_for_each_safe(&cr->sync.monitors, rm, nxt, node)
722 RUBY_DEBUG_LOG(
"port:%u@r%u", (
unsigned int)ractor_port_id(&rm->port), (
unsigned int)rb_ractor_id(rm->port.r));
724 ractor_send_basket(ec, &rm->port, ractor_basket_new_ref(token),
false);
726 ccan_list_del(&rm->node);
730 VM_ASSERT(ccan_list_empty(&cr->sync.monitors));
736ractor_mark_ports_i(st_data_t key, st_data_t val, st_data_t data)
740 ractor_queue_mark(rq);
749 const bool world_stopped = rb_gc_during_global_gc_p();
750 VM_ASSERT(world_stopped || r == rb_current_ractor_raw(
false));
752 rb_gc_mark(r->sync.default_port_value);
758 rb_gc_mark(r->sync.legacy);
766 if (!world_stopped) RACTOR_LOCK_SELF(r);
768 ractor_queue_mark(r->sync.recv_queue);
769 st_foreach(r->sync.ports, ractor_mark_ports_i, 0);
770 ractor_mark_monitors(r);
772 if (!world_stopped) RACTOR_UNLOCK_SELF(r);
780 if (b->type != basket_type_copy)
return;
781 rb_gc_pin_in_flight_message(b->p.v);
782 for (
size_t i = 0; i < b->p.pinned_cnt; i++) {
783 rb_gc_pin_in_flight_message(b->p.pinned[i]);
788ractor_queue_repin_in_flight(
const struct ractor_queue *rq)
791 ccan_list_for_each(&rq->set, b, node) {
794 ractor_basket_repin_in_flight(b);
799ractor_repin_ports_i(st_data_t key, st_data_t val, st_data_t data)
801 ractor_queue_repin_in_flight((
struct ractor_queue *)val);
811 ractor_queue_repin_in_flight(r->sync.recv_queue);
812 st_foreach(r->sync.ports, ractor_repin_ports_i, 0);
815 if (r->sending_basket != NULL) {
816 ractor_basket_repin_in_flight(r->sending_basket);
820 for (
size_t i = 0; i < r->pin_capture_cnt; i++) {
821 rb_gc_pin_in_flight_message(r->pin_capture[i]);
831rb_ractor_mark_in_flight_for_single_objspace(
rb_ractor_t *r)
833 rb_gc_mark(r->sync.legacy);
834 if (r->sending_basket != NULL) {
835 ractor_basket_mark(r->sending_basket);
837 for (
size_t i = 0; i < r->pin_capture_cnt; i++) {
838 rb_gc_mark(r->pin_capture[i]);
843ractor_sync_free_ports_i(st_data_t _key, st_data_t val, st_data_t _args)
847 ractor_queue_free(queue);
855 if (r->sync.recv_queue) {
856 ractor_queue_free(r->sync.recv_queue);
861 st_foreach(r->sync.ports, ractor_sync_free_ports_i, 0);
862 st_free_table(r->sync.ports);
863 r->sync.ports = NULL;
871 return st_memsize(r->sync.ports);
885 ccan_list_head_init(&r->sync.monitors);
888 ccan_list_head_init(&r->sync.waiters);
891 r->sync.recv_queue = ractor_queue_new();
894 r->sync.ports = st_init_numtable();
897 r->sync.default_port_value =
Qfalse;
903 r->sync.materializing_copies = 0;
905#ifndef RUBY_THREAD_PTHREAD_H
915 VM_ASSERT(r->sync.default_port_value ==
Qfalse);
916 r->sync.default_port_value = ractor_port_new(r);
918 rb_gc_obj_became_shareable(r->sync.default_port_value);
926 if (r->sync.successor == NULL) {
927 rb_ractor_t *successor = ATOMIC_PTR_CAS(r->sync.successor, NULL, cr);
928 return successor == NULL ? cr : successor;
931 return r->sync.successor;
935ractor_make_remote_exception(
VALUE cause,
VALUE sender)
939 rb_ec_setup_exception(NULL, err, cause);
948 rb_ractor_t *sr = ractor_set_successor_once(r, cr);
951 if (r->sync.legacy_taken) {
952 rb_raise(rb_eRactorError,
"The value was already taken");
959 while (!rb_ractor_status_p(r, ractor_terminated)) {
965 if (r->sync.legacy_taken) {
966 rb_raise(rb_eRactorError,
"The value was already taken");
971 rb_ractor_absorb_registered_marks(GET_RACTOR(), r);
973 rb_gc_objspace_absorb_into_current(&r->objspace);
977 volatile VALUE legacy_keep = r->sync.legacy;
982 ractor_local_storage_free(r);
983 r->local_storage = NULL;
984 r->idkey_local_storage = NULL;
989 VALUE legacy = r->sync.legacy;
990 r->sync.legacy =
Qnil;
991 r->sync.legacy_taken =
true;
994 if (r->sync.legacy_exc) {
995 rb_exc_raise(ractor_make_remote_exception(legacy, self));
1000 rb_raise(rb_eRactorError,
"Only the successor ractor can take a value");
1004static VALUE ractor_copy_native_try(
VALUE obj);
1007ractor_marshal_dump_body(
VALUE obj)
1013ractor_marshal_dump_rescue(
VALUE obj,
VALUE errinfo)
1015 rb_raise(rb_eRactorError,
"can not copy %"PRIsVALUE
" object.",
rb_class_of(obj));
1023 case basket_type_ref:
1027 *ptype = basket_type_ref;
1034 *ptype = basket_type_copy;
1038 VM_ASSERT(!cr->gen_fields_capturing);
1039 cr->gen_fields_capturing =
true;
1044 enum ruby_tag_type state;
1046 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1047 snapshot = ractor_copy_native_try(obj);
1050 cr->gen_fields_capturing =
false;
1051 if (state != TAG_NONE) {
1052 cr->pin_capture_cnt = 0;
1053 EC_JUMP_TAG(ec, state);
1055 if (UNDEF_P(snapshot)) {
1056 cr->pin_capture_cnt = 0;
1057 snapshot =
rb_rescue2(ractor_marshal_dump_body, obj,
1058 ractor_marshal_dump_rescue, obj,
1074 bool marshaled =
false;
1078 if (type == basket_type_move) {
1081 b = ractor_basket_alloc();
1082 enum ruby_tag_type state;
1084 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1088 courier = rb_ractor_move_courier_build(obj);
1091 if (state != TAG_NONE) {
1093 EC_JUMP_TAG(ec, state);
1097 v = ractor_prepare_payload(ec, obj, &type, &marshaled);
1098 enum ruby_tag_type state;
1100 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1101 b = ractor_basket_alloc();
1104 if (state != TAG_NONE) {
1109 free(cr->pin_capture);
1110 cr->pin_capture = NULL;
1111 cr->pin_capture_cnt = cr->pin_capture_capa = 0;
1112 EC_JUMP_TAG(ec, state);
1118 if (type == basket_type_copy && marshaled) {
1119 rb_gc_pin_in_flight_message(v);
1124 b->p.exception = exc;
1126 b->p.marshaled = marshaled;
1127 b->p.move_courier = courier;
1129 b->p.pinned_cnt = 0;
1130 if (type == basket_type_copy) {
1134 b->p.pinned = cr->pin_capture;
1135 b->p.pinned_cnt = cr->pin_capture_cnt;
1136 VM_ASSERT(cr->sending_basket == NULL);
1137 cr->sending_basket = b;
1138 cr->pin_capture = NULL;
1139 cr->pin_capture_cnt = cr->pin_capture_capa = 0;
1149rb_ractor_materializing_p(
void)
1151 const rb_ractor_t *cr = rb_current_ractor_raw(
false);
1152 if (cr == NULL)
return false;
1156 return cr->sync.materializing_copies > 0;
1163 case basket_type_ref:
1165 case basket_type_copy: {
1180 .snapshot = b->p.v, .pinned = b->p.pinned, .pinned_cnt = b->p.pinned_cnt,
1181 .prev = ec->materialize_frames,
1183 ec->materialize_frames = &frame;
1184 cr->sync.materializing_copies++;
1186 enum ruby_tag_type state;
1188 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1189 if (b->p.marshaled) {
1193 result = ractor_copy_native_try(b->p.v);
1194 if (UNDEF_P(result)) rb_bug(
"ractor_basket_value: native snapshot not natively copyable");
1198 ec->materialize_frames = frame.prev;
1199 cr->sync.materializing_copies--;
1204 ec->gen_fields_cache.obj =
Qundef;
1205 ec->gen_fields_cache.fields_obj =
Qundef;
1206 if (state != TAG_NONE) {
1209 ractor_basket_free(b);
1210 EC_JUMP_TAG(ec, state);
1217 case basket_type_move: {
1235 enum ruby_tag_type state;
1237 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1238 result = rb_ractor_move_courier_materialize(courier);
1241 if (state != TAG_NONE) {
1243 ractor_basket_free(b);
1244 EC_JUMP_TAG(ec, state);
1246 rb_ractor_move_courier_free(courier);
1247 b->p.move_courier = NULL;
1263 VALUE v = ractor_basket_value(b);
1265 if (b->p.exception) {
1266 VALUE err = ractor_make_remote_exception(v, b->sender);
1267 ractor_basket_free(b);
1271 ractor_basket_free(b);
1277#if VM_CHECK_MODE > 0
1281 ASSERT_ractor_locking(cr);
1285 ccan_list_for_each(&cr->sync.waiters, w, node) {
1295#if USE_RUBY_DEBUG_LOG
1298wakeup_status_str(
enum ractor_wakeup_status wakeup_status)
1300 switch (wakeup_status) {
1301 case wakeup_none:
return "none";
1302 case wakeup_by_send:
return "by_send";
1303 case wakeup_by_interrupt:
return "by_interrupt";
1306 rb_bug(
"unreachable");
1310basket_type_name(
enum ractor_basket_type
type)
1313 case basket_type_none:
return "none";
1314 case basket_type_ref:
return "ref";
1315 case basket_type_copy:
return "copy";
1316 case basket_type_move:
return "move";
1324#ifdef RUBY_THREAD_PTHREAD_H
1333#if RACTOR_CHECK_MODE > 0
1334 VALUE locked_by = r->sync.locked_by;
1335 r->sync.locked_by =
Qnil;
1339#if RACTOR_CHECK_MODE > 0
1340 r->sync.locked_by = locked_by;
1345ractor_wait_no_gvl(
void *ptr)
1350 RACTOR_LOCK_SELF(cr);
1352 if (waiter->wakeup_status == wakeup_none) {
1353 ractor_cond_wait(cr);
1356 RACTOR_UNLOCK_SELF(cr);
1367 rb_nogvl(ractor_wait_no_gvl, waiter,
1383ractor_wakeup_all(
rb_ractor_t *r,
enum ractor_wakeup_status wakeup_status)
1385 ASSERT_ractor_unlocking(r);
1387 RUBY_DEBUG_LOG(
"r:%u wakeup:%s", rb_ractor_id(r), wakeup_status_str(wakeup_status));
1389 bool wakeup_p =
false;
1396 VM_ASSERT(waiter->wakeup_status == wakeup_none);
1398 waiter->wakeup_status = wakeup_status;
1399 rb_ractor_sched_wakeup(r, waiter->th);
1413ubf_ractor_wait(
void *ptr)
1422 th->unblock.func = NULL;
1423 th->unblock.arg = NULL;
1429 if (
RUBY_ATOMIC_LOAD(th->unblock.event_serial) == event_serial && waiter->wakeup_status == wakeup_none) {
1430 RUBY_DEBUG_LOG(
"waiter:%p", (
void *)waiter);
1432 waiter->wakeup_status = wakeup_by_interrupt;
1433 ccan_list_del(&waiter->node);
1435 rb_ractor_sched_wakeup(r, waiter->th);
1443static enum ractor_wakeup_status
1449 .wakeup_status = wakeup_none,
1453 RUBY_DEBUG_LOG(
"wait%s",
"");
1455 ASSERT_ractor_locking(cr);
1457 VM_ASSERT(GET_RACTOR() == cr);
1458 VM_ASSERT(!ractor_waiter_included(cr, th));
1460 ccan_list_add_tail(&cr->sync.waiters, &waiter.node);
1463 rb_ractor_sched_wait(ec, cr, ubf_ractor_wait, &waiter);
1465 if (waiter.wakeup_status == wakeup_none) {
1466 ccan_list_del(&waiter.node);
1469 RUBY_DEBUG_LOG(
"wakeup_status:%s", wakeup_status_str(waiter.wakeup_status));
1471 RACTOR_UNLOCK_SELF(cr);
1473 rb_ec_check_ints(ec);
1475 RACTOR_LOCK_SELF(cr);
1477 VM_ASSERT(!ractor_waiter_included(cr, th));
1478 return waiter.wakeup_status;
1484 ASSERT_ractor_locking(cr);
1488 while ((b = ractor_queue_deq(cr, recv_q)) != NULL) {
1489 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
true), b);
1496 struct ractor_queue *received_queue = cr->sync.recv_queue;
1497 bool received =
false;
1499 ASSERT_ractor_locking(cr);
1501 if (ractor_queue_empty_p(cr, received_queue)) {
1502 RUBY_DEBUG_LOG(
"empty");
1508 ractor_queue_init(messages);
1509 ractor_queue_move(messages, received_queue);
1512 VM_ASSERT(ractor_queue_empty_p(cr, received_queue));
1514 RUBY_DEBUG_LOG(
"received:%d", received);
1522 bool deliverred =
false;
1524 RACTOR_LOCK_SELF(cr);
1526 if (ractor_check_received(cr, &messages)) {
1530 ractor_wait(ec, cr);
1533 RACTOR_UNLOCK_SELF(cr);
1536 VM_ASSERT(!ractor_queue_empty_p(cr, &messages));
1539 while ((b = ractor_queue_deq(cr, &messages)) != NULL) {
1540 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
false), b);
1548 struct ractor_queue *rq = ractor_get_queue(cr, ractor_port_id(rp),
false);
1551 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1556 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
1557 ractor_delete_port(cr, ractor_port_id(rp),
false);
1561 return ractor_basket_accept(b);
1572 VM_ASSERT(cr == rp->r);
1574 RUBY_DEBUG_LOG(
"port:%u", (
unsigned int)ractor_port_id(rp));
1577 VALUE v = ractor_try_receive(ec, cr, rp);
1583 ractor_wait_receive(ec, cr);
1593 bool closed =
false;
1595 RUBY_DEBUG_LOG(
"port:%u@r%u b:%s v:%p", (
unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r), basket_type_name(b->type), (
void *)b->p.v);
1599 if (ractor_closed_port_p(ec, rp->r, rp)) {
1603 b->port_id = ractor_port_id(rp);
1604 ractor_queue_enq(rp->r, rp->r->sync.recv_queue, b);
1608 if (b->type == basket_type_copy) {
1610 if (scr != NULL && scr->sending_basket == b) {
1611 scr->sending_basket = NULL;
1616 RACTOR_UNLOCK(rp->r);
1621 ractor_wakeup_all(rp->r, wakeup_by_send);
1624 RUBY_DEBUG_LOG(
"closed:%u@r%u", (
unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r));
1626 if (raise_on_error) {
1627 ractor_basket_free(b);
1628 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1637ractor_basket_new_ref(
VALUE shareable)
1641 b->type = basket_type_ref;
1644 b->p.exception =
false;
1645 b->p.marshaled =
false;
1646 b->p.move_courier = NULL;
1648 b->p.pinned_cnt = 0;
1656 struct ractor_basket *b = ractor_basket_new(ec, obj,
RTEST(move) ? basket_type_move : basket_type_none, false);
1657 ractor_send_basket(ec, rp, b, raise_on_error);
1659 return rp->r->pub.self;
1665 return ractor_send0(ec, rp, obj, move,
true);
1676ractor_selector_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
1678 rb_gc_mark((
VALUE)key);
1684ractor_selector_mark(
void *ptr)
1689 st_foreach(s->ports, ractor_selector_mark_i, 0);
1694ractor_selector_free(
void *ptr)
1697 st_free_table(s->ports);
1702ractor_selector_memsize(
const void *ptr)
1707 size += st_memsize(s->ports);
1715 ractor_selector_mark,
1716 ractor_selector_free,
1717 ractor_selector_memsize,
1720 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
1724RACTOR_SELECTOR_PTR(
VALUE selv)
1726 VM_ASSERT(rb_typeddata_is_kind_of(selv, &ractor_selector_data_type));
1733ractor_selector_create(
VALUE klass)
1737 s->ports = st_init_numtable();
1753 if (!ractor_port_p(rpv)) {
1754 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1758 const struct ractor_port *rp = ractor_port_ptr_check(rpv);
1760 if (st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1761 rb_raise(rb_eArgError,
"already added");
1764 st_insert(s->ports, (st_data_t)rpv, (st_data_t)rp);
1781 if (!ractor_port_p(rpv)) {
1782 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1787 if (!st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1788 rb_raise(rb_eArgError,
"not added yet");
1791 st_delete(s->ports, (st_data_t *)&rpv, NULL);
1805ractor_selector_clear(
VALUE selv)
1819ractor_selector_empty_p(
VALUE selv)
1822 return s->ports->num_entries == 0 ?
Qtrue :
Qfalse;
1836ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t data)
1841 VALUE v = ractor_try_receive(p->ec, p->cr, rp);
1846 p->rpv = (
VALUE)key;
1867 st_foreach(s->ports, ractor_selector_wait_i, (st_data_t)&data);
1870 return rb_ary_new_from_args(2, data.rpv, data.v);
1873 ractor_wait_receive(ec, cr);
1884ractor_selector_wait(
VALUE selector)
1886 return ractor_selector__wait(GET_EC(), selector);
1890ractor_selector_new(
int argc,
VALUE *ractors,
VALUE klass)
1892 VALUE selector = ractor_selector_create(klass);
1894 for (
int i=0; i<argc; i++) {
1895 ractor_selector_add(selector, ractors[i]);
1905 VALUE result = ractor_selector__wait(ec, selector);
1912#ifndef USE_RACTOR_SELECTOR
1913#define USE_RACTOR_SELECTOR 0
1916RUBY_SYMBOL_EXPORT_BEGIN
1917void rb_init_ractor_selector(
void);
1918RUBY_SYMBOL_EXPORT_END
1927rb_init_ractor_selector(
void)
1936 rb_define_method(rb_cRactorSelector,
"empty?", ractor_selector_empty_p, 0);
1941Init_RactorPort(
void)
1946 rb_define_method(rb_cRactorPort,
"initialize_copy", ractor_port_initialize_copy, 1);
1948#if USE_RACTOR_SELECTOR
1949 rb_init_ractor_selector();
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
#define ALLOC
Old name of RB_ALLOC.
#define Qundef
Old name of RUBY_Qundef.
#define ID2SYM
Old name of RB_ID2SYM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define T_NONE
Old name of RUBY_T_NONE.
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_cObject
Object class.
VALUE rb_cRactor
Ractor class.
static VALUE rb_class_of(VALUE obj)
Object to class mapping function.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define rb_exc_new_cstr(exc, str)
Identical to rb_exc_new(), except it assumes the passed pointer is a pointer to a C string.
void rb_unblock_function_t(void *)
This is the type of UBFs.
void rb_thread_schedule(void)
Tries to switch to another thread.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
#define RB_NOGVL_UBF_ASYNC_SAFE
Passing this flag to rb_nogvl() indicates that the passed UBF is async-signal-safe.
#define RB_NOGVL_INTR_FAIL
Passing this flag to rb_nogvl() prevents it from processing interrupts after the given function retur...
void * rb_nogvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int flags)
Identical to rb_thread_call_without_gvl(), except it additionally takes "flags" that change the behav...
VALUE rb_marshal_dump(VALUE obj, VALUE port)
Serialises the given object and all its referring objects, to write them down to the passed port.
VALUE rb_marshal_load(VALUE port)
Deserialises a previous output of rb_marshal_dump() into a network of objects.
#define RBIMPL_ATTR_MAYBE_UNUSED()
Wraps (or simulates) [[maybe_unused]]
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_cond_initialize(rb_nativethread_cond_t *cond)
Fills the passed condition variable with an initial value.
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_initialize.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
Waits for the passed condition variable to be signalled.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.