14static VALUE rb_cRactorPort;
20static void ractor_add_port(
rb_ractor_t *r, st_data_t
id);
31static void ractor_port_note_alive(
const struct ractor_port *rp);
34ractor_port_mark(
void *ptr)
39 rb_gc_mark(rp->r->pub.self);
44 if (rb_gc_single_objspace_p() || rb_gc_during_global_gc_p()) {
45 ractor_port_note_alive(rp);
58 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
65 return cr->sync.next_port_id++;
69RACTOR_PORT_PTR(
VALUE self)
71 VM_ASSERT(rb_typeddata_is_kind_of(self, &ractor_port_data_type));
72 return RTYPEDDATA_GET_DATA(self);
77ractor_port_ptr_check(
VALUE self)
81 if (UNLIKELY(rp->r == NULL)) {
89ractor_port_alloc(
VALUE klass)
102 if (!r->sync.ports) {
103 rb_raise(rb_eRactorClosedError,
"The ractor has terminated");
110 rp->id_ = ractor_genid_for_port(r);
112 ractor_add_port(r, ractor_port_id(rp));
126ractor_port_initialize(
VALUE self)
128 return ractor_port_init(self, GET_RACTOR());
133ractor_port_initialize_copy(
VALUE self,
VALUE orig)
136 struct ractor_port *src = ractor_port_ptr_check(orig);
139 dst->id_ = ractor_port_id(src);
147 VALUE rpv = ractor_port_alloc(rb_cRactorPort);
148 ractor_port_init(rpv, r);
153ractor_port_p(
VALUE self)
155 return rb_typeddata_is_kind_of(self, &ractor_port_data_type);
158static const rb_hrtime_t *ractor_timeout_deadline(
VALUE timeout, rb_hrtime_t *storage);
163 const struct ractor_port *rp = ractor_port_ptr_check(self);
165 if (rp->r != rb_ec_ractor_ptr(ec)) {
166 rb_raise(rb_eRactorError,
"only allowed from the creator Ractor of this port");
169 rb_hrtime_t deadline;
170 const rb_hrtime_t *end = ractor_timeout_deadline(timeout, &deadline);
172 VALUE v = ractor_receive(ec, rp, end);
176 return UNDEF_P(v) ?
Qnil : v;
182 const struct ractor_port *rp = ractor_port_ptr_check(self);
183 ractor_send(ec, rp, obj,
RTEST(move));
194 const struct ractor_port *rp = ractor_port_ptr_check(self);
198 if (rb_ec_ractor_ptr(ec) == r) {
201 closed = ractor_closed_port_p(ec, r, rp);
210 closed = ractor_closed_port_p(ec, r, rp);
221 const struct ractor_port *rp = ractor_port_ptr_check(self);
225 rb_raise(rb_eRactorError,
"closing port by other ractors is not allowed");
228 ractor_close_port(ec, cr, rp);
236enum ractor_basket_type {
263 struct ccan_list_node node;
265 enum ractor_basket_type type : 8;
272ractor_basket_type_p(
const struct ractor_basket *b,
enum ractor_basket_type type)
274 return b->type == type;
280 return ractor_basket_type_p(b, basket_type_none);
287 if (b->has_courier) {
292 rb_ractor_courier_mark(ctx, b->p.courier);
305 ractor_off_queue_remove(b);
306 if (b->has_courier && b->p.courier) {
308 rb_ractor_courier_free(b->p.courier);
315ractor_basket_alloc(
void)
321 b->type = basket_type_none;
325 b->has_courier =
false;
326 b->exception =
false;
327 ccan_list_node_init(&b->node);
337 VM_ASSERT(cr == rb_current_ractor_raw(
false));
338 ccan_list_add_tail(&cr->sync.off_queue_baskets, &b->node);
344 ccan_list_del_init(&b->node);
351 ccan_list_for_each(&r->sync.off_queue_baskets, b, node) {
352 ractor_basket_mark(ctx, b);
359 struct ccan_list_head set;
367 ccan_list_head_init(&rq->set);
373ractor_queue_new(
void)
376 ractor_queue_init(rq);
381ractor_port_note_alive(
const struct ractor_port *rp)
385 if (rp->r->sync.ports && st_lookup(rp->r->sync.ports, rp->id_, (st_data_t *)&rq)) {
398 ccan_list_for_each(&rq->set, b, node) {
399 ractor_basket_mark(ctx, b);
408 ccan_list_for_each_safe(&rq->set, b, nxt, node) {
409 ccan_list_del_init(&b->node);
410 ractor_basket_free(b);
413 VM_ASSERT(ccan_list_empty(&rq->set));
425 ccan_list_for_each(&rq->set, b, node) {
435 bool closed_now = !rq->closed;
443 struct ccan_list_head *src = &src_rq->set;
444 struct ccan_list_head *dst = &dst_rq->set;
446 dst->n.next = src->n.next;
447 dst->n.prev = src->n.prev;
448 dst->n.next->prev = &dst->n;
449 dst->n.prev->next = &dst->n;
450 ccan_list_head_init(src);
464 return ccan_list_empty(&rq->set);
470 VM_ASSERT(GET_RACTOR() == r);
473 if (b) ccan_list_node_init(&b->node);
480 ccan_list_add_tail(&rq->set, &basket->node);
489 ccan_list_for_each(&rq->set, b, node) {
490 fprintf(stderr,
"%d type:%s %p\n", i, basket_type_name(b->type), (
void *)b);
496static void ractor_delete_port(
rb_ractor_t *cr, st_data_t
id,
bool locked);
499ractor_get_queue(
rb_ractor_t *cr, st_data_t
id,
bool locked)
501 VM_ASSERT(cr == GET_RACTOR());
505 if (cr->sync.ports && st_lookup(cr->sync.ports,
id, (st_data_t *)&rq)) {
506 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
507 ractor_delete_port(cr,
id, locked);
525 ASSERT_ractor_unlocking(r);
527 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
531 st_table *
const old_tab = r->sync.ports;
536 inserted = st_insert_no_rebuild(old_tab,
id, (st_data_t)rq) >= 0;
553 const st_index_t entries = st_table_size(old_tab);
555 new_tab = st_copy(old_tab);
557 if (st_table_size(old_tab) == entries) {
558 st_insert(new_tab,
id, (st_data_t)rq);
560 if (st_table_size(old_tab) == entries)
break;
563 st_free_table(new_tab);
568 VM_ASSERT(r->sync.ports == old_tab);
569 r->sync.ports = new_tab;
573 st_free_table(old_tab);
578ractor_delete_port_locked(
rb_ractor_t *cr, st_data_t
id)
580 ASSERT_ractor_locking(cr);
582 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
586 if (st_delete(cr->sync.ports, &
id, (st_data_t *)&rq)) {
587 ractor_queue_free(rq);
595ractor_delete_port(
rb_ractor_t *cr, st_data_t
id,
bool locked)
598 ractor_delete_port_locked(cr,
id);
601 RACTOR_LOCK_SELF(cr);
603 ractor_delete_port_locked(cr,
id);
605 RACTOR_UNLOCK_SELF(cr);
612 return RACTOR_PORT_PTR(r->sync.default_port_value);
618 return r->sync.default_port_value;
624 VM_ASSERT(rb_ec_ractor_ptr(ec) == rp->r ? 1 : (ASSERT_ractor_locking(rp->r), 1));
628 if (rp->r->sync.ports && st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
639static bool ractor_wakeup_all(
rb_ractor_t *r,
enum ractor_wakeup_status wakeup_status);
644 VM_ASSERT(cr == rp->r);
646 bool closed_now =
false;
648 RACTOR_LOCK_SELF(cr);
650 ractor_deliver_incoming_messages(ec, cr);
652 if (st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
653 closed_now = ractor_queue_close(rq);
655 if (ractor_queue_empty_p(cr, rq)) {
657 ractor_delete_port(cr, ractor_port_id(rp),
true);
663 RACTOR_UNLOCK_SELF(cr);
668 ractor_wakeup_all(cr, wakeup_by_close);
678ractor_reap_dead_ports_i(st_data_t port_id, st_data_t val, st_data_t dat)
687 ractor_queue_free(rq);
699 if (recv_q == NULL)
return;
702 ccan_list_for_each_safe(&recv_q->set, b, nxt, node) {
703 if (!st_lookup(r->sync.ports, b->port_id, NULL)) {
704 ccan_list_del_init(&b->node);
705 ractor_basket_free(b);
714 VM_ASSERT(rb_gc_single_objspace_p() || rb_gc_during_global_gc_p());
717 st_foreach(r->sync.ports, ractor_reap_dead_ports_i, 0);
718 ractor_reap_undeliverable_messages(r);
723ractor_free_all_ports_i(st_data_t port_id, st_data_t val, st_data_t dat)
728 ractor_queue_free(rq);
735 if (cr->sync.ports) {
736 st_foreach(cr->sync.ports, ractor_free_all_ports_i, (st_data_t)cr);
737 st_free_table(cr->sync.ports);
738 cr->sync.ports = NULL;
741 if (cr->sync.recv_queue) {
742 ractor_queue_free(cr->sync.recv_queue);
743 cr->sync.recv_queue = NULL;
747#if defined(HAVE_WORKING_FORK)
751 ractor_free_all_ports(r);
752 r->sync.legacy =
Qnil;
760 struct ccan_list_node node;
770 ccan_list_for_each(&r->sync.monitors, rm, node) {
780 if (r->sync.legacy_exc) {
781 RUBY_DEBUG_LOG(
"aborted");
785 RUBY_DEBUG_LOG(
"exited");
794 bool terminated =
false;
795 const struct ractor_port *rp = ractor_port_ptr_check(port);
801 if (UNDEF_P(r->sync.legacy)) {
802 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));
803 ccan_list_add_tail(&r->sync.monitors, &rm->node);
806 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));
814 ractor_send_basket(ec, rp, ractor_basket_new_exit(self, ractor_exit_token(r)),
false);
830 alive = UNDEF_P(r->sync.legacy);
835 return RBOOL(alive && !rb_ractor_status_p(r, ractor_terminated));
842 const struct ractor_port *rp = ractor_port_ptr_check(port);
846 if (UNDEF_P(r->sync.legacy)) {
849 ccan_list_for_each_safe(&r->sync.monitors, rm, nxt, node) {
850 if (rm->port.r == rp->r && ractor_port_id(&rm->port) == ractor_port_id(rp)) {
851 RUBY_DEBUG_LOG(
"r:%u -> port:%u@r%u",
852 (
unsigned int)rb_ractor_id(r),
853 (
unsigned int)ractor_port_id(&rm->port),
854 (
unsigned int)rb_ractor_id(rm->port.r));
855 ccan_list_del(&rm->node);
869 RUBY_DEBUG_LOG(
"exc:%d", exc);
870 VM_ASSERT(!UNDEF_P(legacy));
871 VM_ASSERT(cr->sync.legacy ==
Qundef);
873 RACTOR_LOCK_SELF(cr);
875 ractor_free_all_ports(cr);
877 cr->sync.legacy = legacy;
878 cr->sync.legacy_exc = exc;
880 RACTOR_UNLOCK_SELF(cr);
889 VALUE token = ractor_exit_token(cr);
892 ccan_list_for_each_safe(&cr->sync.monitors, rm, nxt, node)
894 RUBY_DEBUG_LOG(
"port:%u@r%u", (
unsigned int)ractor_port_id(&rm->port), (
unsigned int)rb_ractor_id(rm->port.r));
896 ractor_send_basket(ec, &rm->port, ractor_basket_new_exit(cr->pub.self, token),
false);
898 ccan_list_del(&rm->node);
902 VM_ASSERT(ccan_list_empty(&cr->sync.monitors));
908ractor_mark_ports_i(st_data_t key, st_data_t val, st_data_t data)
921 const bool world_stopped = rb_gc_during_global_gc_p();
922 VM_ASSERT(world_stopped || r == rb_current_ractor_raw(
false));
936 if (!world_stopped) RACTOR_LOCK_SELF(r);
938 ractor_queue_mark(ctx, r->sync.recv_queue);
939 st_foreach(r->sync.ports, ractor_mark_ports_i, (st_data_t)ctx);
940 ractor_mark_monitors(ctx, r);
942 if (!world_stopped) RACTOR_UNLOCK_SELF(r);
953 ractor_mark_off_queue_baskets(ctx, r);
958ractor_sync_free_ports_i(st_data_t _key, st_data_t val, st_data_t _args)
962 ractor_queue_free(queue);
970 if (r->sync.recv_queue) {
971 ractor_queue_free(r->sync.recv_queue);
976 st_foreach(r->sync.ports, ractor_sync_free_ports_i, 0);
977 st_free_table(r->sync.ports);
978 r->sync.ports = NULL;
986 return st_memsize(r->sync.ports);
1000 ccan_list_head_init(&r->sync.off_queue_baskets);
1001 ccan_list_head_init(&r->sync.monitors);
1004 ccan_list_head_init(&r->sync.waiters);
1007 r->sync.recv_queue = ractor_queue_new();
1010 r->sync.ports = st_init_numtable();
1013 r->sync.default_port_value =
Qfalse;
1027 VM_ASSERT(r->sync.default_port_value ==
Qfalse);
1028 r->sync.default_port_value = ractor_port_new(r);
1037 if (r->sync.successor == NULL) {
1038 rb_ractor_t *successor = ATOMIC_PTR_CAS(r->sync.successor, NULL, cr);
1039 return successor == NULL ? cr : successor;
1042 return r->sync.successor;
1046ractor_make_remote_exception(
VALUE cause,
VALUE sender)
1050 rb_ec_setup_exception(NULL, err, cause);
1059 rb_ractor_t *sr = ractor_set_successor_once(r, cr);
1062 if (r->sync.legacy_taken) {
1063 rb_raise(rb_eRactorError,
"The value was already taken");
1070 while (!rb_ractor_status_p(r, ractor_terminated)) {
1076 if (r->sync.legacy_taken) {
1077 rb_raise(rb_eRactorError,
"The value was already taken");
1082 rb_ractor_absorb_registered_marks(GET_RACTOR(), r);
1083 rb_ractor_absorb_registered_addrs_without_gc(GET_RACTOR(), r);
1085 rb_gc_objspace_absorb_into_current(&r->objspace);
1089 volatile VALUE legacy_keep = r->sync.legacy;
1094 ractor_local_storage_free(r);
1095 r->local_storage = NULL;
1096 r->idkey_local_storage = NULL;
1101 VALUE legacy = r->sync.legacy;
1102 r->sync.legacy =
Qnil;
1103 r->sync.legacy_taken =
true;
1106 if (r->sync.legacy_exc) {
1107 rb_exc_raise(ractor_make_remote_exception(legacy, self));
1112 rb_raise(rb_eRactorError,
"Only the successor ractor can take a value");
1117ractor_marshal_dump_body(
VALUE obj)
1123ractor_marshal_dump_rescue(
VALUE obj,
VALUE errinfo)
1125 rb_raise(rb_eRactorError,
"can not copy %"PRIsVALUE
" object.",
rb_class_of(obj));
1134 case basket_type_ref:
1138 *ptype = basket_type_ref;
1146 *ptype = basket_type_copy;
1147 if (rb_ractor_courier_build_copy(obj, pcourier) == NULL) {
1148 rb_raise(rb_eRactorError,
"can not copy %"PRIsVALUE
" object.",
rb_class_of(obj));
1155#if RBIMPL_COMPILER_IS(GCC) && defined(__OPTIMIZE__)
1162 enum ractor_basket_type type,
bool exc)
1166 b->p.courier = NULL;
1167 b->has_courier =
true;
1169 if (type == basket_type_move) {
1174 rb_ractor_courier_build_move(obj, &b->p.courier);
1178 VALUE v = ractor_prepare_payload(ec, obj, &type, &b->p.courier);
1179 if (b->p.courier == NULL) {
1180 b->has_courier =
false;
1195 ractor_off_queue_add(cr, b);
1197 enum ruby_tag_type state;
1199 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1200 ractor_basket_build_payload(ec, b, obj, type, exc);
1203 if (state != TAG_NONE) {
1204 ractor_basket_free(b);
1205 EC_JUMP_TAG(ec, state);
1215 case basket_type_ref:
1217 case basket_type_exit:
1219 return rb_ary_new_from_args(2, b->sender, b->p.v);
1220 case basket_type_copy:
1223 case basket_type_move: {
1241 enum ruby_tag_type state;
1243 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1244 result = rb_ractor_courier_materialize(courier);
1247 if (state != TAG_NONE) {
1249 ractor_basket_free(b);
1250 EC_JUMP_TAG(ec, state);
1252 rb_ractor_courier_free(courier);
1253 b->p.courier = NULL;
1254 b->has_courier =
false;
1263 VM_ASSERT(!b->has_courier);
1271 VALUE v = ractor_basket_value(b);
1274 VALUE err = ractor_make_remote_exception(v, b->sender);
1275 ractor_basket_free(b);
1279 ractor_basket_free(b);
1285#if VM_CHECK_MODE > 0
1289 ASSERT_ractor_locking(cr);
1293 ccan_list_for_each(&cr->sync.waiters, w, node) {
1303#if USE_RUBY_DEBUG_LOG
1306wakeup_status_str(
enum ractor_wakeup_status wakeup_status)
1308 switch (wakeup_status) {
1309 case wakeup_none:
return "none";
1310 case wakeup_by_send:
return "by_send";
1311 case wakeup_by_interrupt:
return "by_interrupt";
1312 case wakeup_by_close:
return "by_close";
1314 rb_bug(
"unreachable");
1318basket_type_name(
enum ractor_basket_type
type)
1321 case basket_type_none:
return "none";
1322 case basket_type_ref:
return "ref";
1323 case basket_type_copy:
return "copy";
1324 case basket_type_move:
return "move";
1325 case basket_type_exit:
return "exit";
1334ractor_wakeup_all_locked(
rb_ractor_t *r,
enum ractor_wakeup_status wakeup_status)
1336 ASSERT_ractor_locking(r);
1338 RUBY_DEBUG_LOG(
"r:%"PRI_SERIALT_PREFIX
"u wakeup:%s", rb_ractor_id(r), wakeup_status_str(wakeup_status));
1340 bool wakeup_p =
false;
1346 VM_ASSERT(waiter->wakeup_status == wakeup_none);
1348 waiter->wakeup_status = wakeup_status;
1349 rb_ractor_sched_wakeup(r, waiter->th);
1362ractor_wakeup_all(
rb_ractor_t *r,
enum ractor_wakeup_status wakeup_status)
1364 ASSERT_ractor_unlocking(r);
1370 wakeup_p = ractor_wakeup_all_locked(r, wakeup_status);
1378ubf_ractor_wait(
void *ptr)
1387 th->unblock.func = NULL;
1388 th->unblock.arg = NULL;
1394 if (
RUBY_ATOMIC_LOAD(th->unblock.event_serial) == event_serial && waiter->wakeup_status == wakeup_none) {
1395 RUBY_DEBUG_LOG(
"waiter:%p", (
void *)waiter);
1397 waiter->wakeup_status = wakeup_by_interrupt;
1398 ccan_list_del(&waiter->node);
1400 rb_ractor_sched_wakeup(r, waiter->th);
1409static enum ractor_wakeup_status
1415 .wakeup_status = wakeup_none,
1420 RUBY_DEBUG_LOG(
"wait%s",
"");
1422 ASSERT_ractor_locking(cr);
1424 VM_ASSERT(GET_RACTOR() == cr);
1425 VM_ASSERT(!ractor_waiter_included(cr, th));
1427 ccan_list_add_tail(&cr->sync.waiters, &waiter.node);
1430 rb_ractor_sched_wait(ec, cr, ubf_ractor_wait, &waiter);
1432 if (waiter.wakeup_status == wakeup_none) {
1433 ccan_list_del(&waiter.node);
1436 RUBY_DEBUG_LOG(
"wakeup_status:%s", wakeup_status_str(waiter.wakeup_status));
1438 RACTOR_UNLOCK_SELF(cr);
1440 rb_ec_check_ints(ec);
1442 RACTOR_LOCK_SELF(cr);
1444 VM_ASSERT(!ractor_waiter_included(cr, th));
1445 return waiter.wakeup_status;
1451 ASSERT_ractor_locking(cr);
1455 while ((b = ractor_queue_deq(cr, recv_q)) != NULL) {
1456 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
true), b);
1463 struct ractor_queue *received_queue = cr->sync.recv_queue;
1464 bool received =
false;
1466 ASSERT_ractor_locking(cr);
1468 if (ractor_queue_empty_p(cr, received_queue)) {
1469 RUBY_DEBUG_LOG(
"empty");
1475 ractor_queue_init(messages);
1476 ractor_queue_move(messages, received_queue);
1479 VM_ASSERT(ractor_queue_empty_p(cr, received_queue));
1481 RUBY_DEBUG_LOG(
"received:%d", received);
1490ractor_deadline_passed_p(
const rb_hrtime_t *end)
1492 return end != NULL && rb_hrtime_now() >= *end;
1499 bool deliverred =
false;
1500 bool timedout =
false;
1502 RACTOR_LOCK_SELF(cr);
1504 if (ractor_check_received(cr, &messages)) {
1508 ractor_wait(ec, cr, NULL);
1510 else if (*end == 0) {
1516 timedout = ractor_wait(ec, cr, end) == wakeup_none && rb_hrtime_now() >= *end;
1519 RACTOR_UNLOCK_SELF(cr);
1522 VM_ASSERT(!ractor_queue_empty_p(cr, &messages));
1525 while ((b = ractor_queue_deq(cr, &messages)) != NULL) {
1526 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
false), b);
1536 struct ractor_queue *rq = ractor_get_queue(cr, ractor_port_id(rp),
false);
1539 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1544 if (b) ractor_off_queue_add(cr, b);
1546 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
1547 ractor_delete_port(cr, ractor_port_id(rp),
false);
1551 return ractor_basket_accept(b);
1566 VM_ASSERT(cr == rp->r);
1568 RUBY_DEBUG_LOG(
"port:%u", (
unsigned int)ractor_port_id(rp));
1571 VALUE v = ractor_try_receive(ec, cr, rp);
1576 else if (!ractor_wait_receive(ec, cr, end)) {
1579 else if (ractor_deadline_passed_p(end)) {
1582 return ractor_try_receive(ec, cr, rp);
1589static const rb_hrtime_t *
1590ractor_timeout_deadline(
VALUE timeout, rb_hrtime_t *storage)
1592 if (
NIL_P(timeout))
return NULL;
1596 rb_hrtime_t rel = rb_timeval2hrtime(&tv);
1599 *storage = rb_hrtime_add(rb_hrtime_now(), rel);
1613 bool closed =
false;
1615 RUBY_DEBUG_LOG(
"port:%u@r%"PRI_SERIALT_PREFIX
"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);
1619 if (ractor_closed_port_p(ec, rp->r, rp)) {
1623 b->port_id = ractor_port_id(rp);
1625 ractor_off_queue_remove(b);
1626 ractor_queue_enq(rp->r, rp->r->sync.recv_queue, b);
1627 ractor_wakeup_all_locked(rp->r, wakeup_by_send);
1630 RACTOR_UNLOCK(rp->r);
1635 RUBY_DEBUG_LOG(
"closed:%u@r%"PRI_SERIALT_PREFIX
"u", (
unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r));
1639 ractor_basket_free(b);
1641 if (raise_on_error) {
1642 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1652ractor_basket_new_exit(
VALUE sender,
VALUE token)
1656 b->type = basket_type_exit;
1666 struct ractor_basket *b = ractor_basket_new(ec, obj,
RTEST(move) ? basket_type_move : basket_type_none, false);
1667 ractor_send_basket(ec, rp, b, raise_on_error);
1669 return rp->r->pub.self;
1675 return ractor_send0(ec, rp, obj, move,
true);
1686ractor_selector_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
1688 rb_gc_mark((
VALUE)key);
1694ractor_selector_mark(
void *ptr)
1699 st_foreach(s->ports, ractor_selector_mark_i, 0);
1704ractor_selector_free(
void *ptr)
1707 st_free_table(s->ports);
1712ractor_selector_memsize(
const void *ptr)
1717 size += st_memsize(s->ports);
1725 ractor_selector_mark,
1726 ractor_selector_free,
1727 ractor_selector_memsize,
1730 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
1734RACTOR_SELECTOR_PTR(
VALUE selv)
1736 VM_ASSERT(rb_typeddata_is_kind_of(selv, &ractor_selector_data_type));
1743ractor_selector_create(
VALUE klass)
1747 s->ports = st_init_numtable();
1763 if (!ractor_port_p(rpv)) {
1764 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1768 const struct ractor_port *rp = ractor_port_ptr_check(rpv);
1770 if (st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1771 rb_raise(rb_eArgError,
"already added");
1774 st_insert(s->ports, (st_data_t)rpv, (st_data_t)rp);
1791 if (!ractor_port_p(rpv)) {
1792 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1797 if (!st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1798 rb_raise(rb_eArgError,
"not added yet");
1801 st_delete(s->ports, (st_data_t *)&rpv, NULL);
1815ractor_selector_clear(
VALUE selv)
1829ractor_selector_empty_p(
VALUE selv)
1832 return s->ports->num_entries == 0 ?
Qtrue :
Qfalse;
1846ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t data)
1851 VALUE v = ractor_try_receive(p->ec, p->cr, rp);
1856 p->rpv = (
VALUE)key;
1877 st_foreach(s->ports, ractor_selector_wait_i, (st_data_t)&data);
1880 return rb_ary_new_from_args(2, data.rpv, data.v);
1882 else if (!ractor_wait_receive(ec, cr, end)) {
1885 else if (ractor_deadline_passed_p(end)) {
1886 st_foreach(s->ports, ractor_selector_wait_i, (st_data_t)&data);
1887 return data.found ? rb_ary_new_from_args(2, data.rpv, data.v) :
Qnil;
1899ractor_selector_wait(
VALUE selector)
1901 return ractor_selector__wait(GET_EC(), selector, NULL);
1905ractor_selector_new(
int argc,
VALUE *ractors,
VALUE klass)
1907 VALUE selector = ractor_selector_create(klass);
1909 for (
int i=0; i<argc; i++) {
1910 ractor_selector_add(selector, ractors[i]);
1919 rb_hrtime_t deadline;
1920 const rb_hrtime_t *end = ractor_timeout_deadline(timeout, &deadline);
1923 VALUE result = ractor_selector__wait(ec, selector, end);
1930#ifndef USE_RACTOR_SELECTOR
1931#define USE_RACTOR_SELECTOR 0
1934RUBY_SYMBOL_EXPORT_BEGIN
1935void rb_init_ractor_selector(
void);
1936RUBY_SYMBOL_EXPORT_END
1945rb_init_ractor_selector(
void)
1954 rb_define_method(rb_cRactorSelector,
"empty?", ractor_selector_empty_p, 0);
1959Init_RactorPort(
void)
1964 rb_define_method(rb_cRactorPort,
"initialize_copy", ractor_port_initialize_copy, 1);
1966#if USE_RACTOR_SELECTOR
1967 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.
#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 FIX2LONG
Old name of RB_FIX2LONG.
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
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)
Same as RB_OBJ_FREEZE(), but returns the given object.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
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.
#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_thread_schedule(void)
Tries to switch to another thread.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
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.
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
#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_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.
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.