15static VALUE rb_cRactorPort;
17static VALUE ractor_receive(rb_execution_context_t *ec,
const struct ractor_port *rp);
20static void ractor_add_port(rb_ractor_t *r, st_data_t
id);
23ractor_port_mark(
void *ptr)
28 rb_gc_mark(rp->r->pub.self);
33ractor_port_free(
void *ptr)
39ractor_port_memsize(
const void *ptr)
52 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
56ractor_genid_for_port(rb_ractor_t *cr)
59 return cr->sync.next_port_id++;
63RACTOR_PORT_PTR(
VALUE self)
71ractor_port_alloc(
VALUE klass)
80ractor_port_init(
VALUE rpv, rb_ractor_t *r)
86 rp->id_ = ractor_genid_for_port(r);
88 ractor_add_port(r, ractor_port_id(rp));
102ractor_port_initialize(
VALUE self)
104 return ractor_port_init(self, GET_RACTOR());
109ractor_port_initialize_copy(
VALUE self,
VALUE orig)
115 dst->id_ = ractor_port_id(src);
121ractor_port_new(rb_ractor_t *r)
123 VALUE rpv = ractor_port_alloc(rb_cRactorPort);
124 ractor_port_init(rpv, r);
129ractor_port_p(
VALUE self)
135ractor_port_receive(rb_execution_context_t *ec,
VALUE self)
137 const struct ractor_port *rp = RACTOR_PORT_PTR(self);
139 if (rp->r != rb_ec_ractor_ptr(ec)) {
140 rb_raise(rb_eRactorError,
"only allowed from the creator Ractor of this port");
143 return ractor_receive(ec, rp);
147ractor_port_send(rb_execution_context_t *ec,
VALUE self,
VALUE obj,
VALUE move)
149 const struct ractor_port *rp = RACTOR_PORT_PTR(self);
150 ractor_send(ec, rp, obj,
RTEST(move));
154static bool ractor_closed_port_p(rb_execution_context_t *ec, rb_ractor_t *r,
const struct ractor_port *rp);
155static bool ractor_close_port(rb_execution_context_t *ec, rb_ractor_t *r,
const struct ractor_port *rp);
158ractor_port_closed_p(rb_execution_context_t *ec,
VALUE self)
160 const struct ractor_port *rp = RACTOR_PORT_PTR(self);
162 if (ractor_closed_port_p(ec, rp->r, rp)) {
171ractor_port_close(rb_execution_context_t *ec,
VALUE self)
173 const struct ractor_port *rp = RACTOR_PORT_PTR(self);
174 rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
177 rb_raise(rb_eRactorError,
"closing port by other ractors is not allowed");
180 ractor_close_port(ec, cr, rp);
188enum ractor_basket_type {
199 enum ractor_basket_type type;
208 struct ccan_list_node node;
213ractor_basket_type_p(
const struct ractor_basket *b,
enum ractor_basket_type type)
215 return b->type == type;
221 return ractor_basket_type_p(b, basket_type_none);
238ractor_basket_alloc(
void)
247 struct ccan_list_head set;
254 ccan_list_head_init(&rq->set);
259ractor_queue_new(
void)
262 ractor_queue_init(rq);
271 ccan_list_for_each(&rq->set, b, node) {
272 ractor_basket_mark(b);
281 ccan_list_for_each_safe(&rq->set, b, nxt, node) {
282 ccan_list_del_init(&b->node);
283 ractor_basket_free(b);
286 VM_ASSERT(ccan_list_empty(&rq->set));
298 ccan_list_for_each(&rq->set, b, node) {
313 struct ccan_list_head *src = &src_rq->set;
314 struct ccan_list_head *dst = &dst_rq->set;
316 dst->n.next = src->n.next;
317 dst->n.prev = src->n.prev;
318 dst->n.next->prev = &dst->n;
319 dst->n.prev->next = &dst->n;
320 ccan_list_head_init(src);
325ractor_queue_head(rb_ractor_t *r,
struct ractor_queue *rq)
332ractor_queue_empty_p(rb_ractor_t *r,
const struct ractor_queue *rq)
334 return ccan_list_empty(&rq->set);
338ractor_queue_deq(rb_ractor_t *r,
struct ractor_queue *rq)
340 VM_ASSERT(GET_RACTOR() == r);
348 ccan_list_add_tail(&rq->set, &basket->node);
357 ccan_list_for_each(&rq->set, b, node) {
358 fprintf(stderr,
"%d type:%s %p\n", i, basket_type_name(b->type), (
void *)b);
364static void ractor_delete_port(rb_ractor_t *cr, st_data_t
id,
bool locked);
367ractor_get_queue(rb_ractor_t *cr, st_data_t
id,
bool locked)
369 VM_ASSERT(cr == GET_RACTOR());
373 if (cr->sync.ports && st_lookup(cr->sync.ports,
id, (st_data_t *)&rq)) {
374 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
375 ractor_delete_port(cr,
id, locked);
390ractor_add_port(rb_ractor_t *r, st_data_t
id)
393 ASSERT_ractor_unlocking(r);
395 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
399 st_insert(r->sync.ports,
id, (st_data_t)rq);
405ractor_delete_port_locked(rb_ractor_t *cr, st_data_t
id)
407 ASSERT_ractor_locking(cr);
409 RUBY_DEBUG_LOG(
"id:%u", (
unsigned int)
id);
413 if (st_delete(cr->sync.ports, &
id, (st_data_t *)&rq)) {
414 ractor_queue_free(rq);
422ractor_delete_port(rb_ractor_t *cr, st_data_t
id,
bool locked)
425 ractor_delete_port_locked(cr,
id);
428 RACTOR_LOCK_SELF(cr);
430 ractor_delete_port_locked(cr,
id);
432 RACTOR_UNLOCK_SELF(cr);
437ractor_default_port(rb_ractor_t *r)
439 return RACTOR_PORT_PTR(r->sync.default_port_value);
443ractor_default_port_value(rb_ractor_t *r)
445 return r->sync.default_port_value;
449ractor_closed_port_p(rb_execution_context_t *ec, rb_ractor_t *r,
const struct ractor_port *rp)
451 VM_ASSERT(rb_ec_ractor_ptr(ec) == rp->r ? 1 : (ASSERT_ractor_locking(rp->r), 1));
455 if (rp->r->sync.ports && st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
463static void ractor_deliver_incoming_messages(rb_execution_context_t *ec, rb_ractor_t *cr);
464static bool ractor_queue_empty_p(rb_ractor_t *r,
const struct ractor_queue *rq);
467ractor_close_port(rb_execution_context_t *ec, rb_ractor_t *cr,
const struct ractor_port *rp)
469 VM_ASSERT(cr == rp->r);
472 RACTOR_LOCK_SELF(cr);
474 ractor_deliver_incoming_messages(ec, cr);
476 if (st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
477 ractor_queue_close(rq);
479 if (ractor_queue_empty_p(cr, rq)) {
481 ractor_delete_port(cr, ractor_port_id(rp),
true);
487 RACTOR_UNLOCK_SELF(cr);
493ractor_free_all_ports_i(st_data_t port_id, st_data_t val, st_data_t dat)
498 ractor_queue_free(rq);
503ractor_free_all_ports(rb_ractor_t *cr)
505 if (cr->sync.ports) {
506 st_foreach(cr->sync.ports, ractor_free_all_ports_i, (st_data_t)cr);
507 st_free_table(cr->sync.ports);
508 cr->sync.ports = NULL;
511 if (cr->sync.recv_queue) {
512 ractor_queue_free(cr->sync.recv_queue);
513 cr->sync.recv_queue = NULL;
517#if defined(HAVE_WORKING_FORK)
519ractor_sync_terminate_atfork(rb_vm_t *vm, rb_ractor_t *r)
521 ractor_free_all_ports(r);
522 r->sync.legacy =
Qnil;
530 struct ccan_list_node node;
534ractor_mark_monitors(rb_ractor_t *r)
537 ccan_list_for_each(&r->sync.monitors, rm, node) {
538 rb_gc_mark(rm->port.r->pub.self);
543ractor_exit_token(
bool exc)
546 RUBY_DEBUG_LOG(
"aborted");
550 RUBY_DEBUG_LOG(
"exited");
558 rb_ractor_t *r = RACTOR_PTR(self);
559 bool terminated =
false;
560 const struct ractor_port *rp = RACTOR_PORT_PTR(port);
566 if (UNDEF_P(r->sync.legacy)) {
567 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));
568 ccan_list_add_tail(&r->sync.monitors, &rm->node);
571 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));
579 ractor_port_send(ec, port, ractor_exit_token(r->sync.legacy_exc),
Qfalse);
589ractor_unmonitor(rb_execution_context_t *ec,
VALUE self,
VALUE port)
591 rb_ractor_t *r = RACTOR_PTR(self);
592 const struct ractor_port *rp = RACTOR_PORT_PTR(port);
596 if (UNDEF_P(r->sync.legacy)) {
599 ccan_list_for_each_safe(&r->sync.monitors, rm, nxt, node) {
600 if (ractor_port_id(&rm->port) == ractor_port_id(rp)) {
601 RUBY_DEBUG_LOG(
"r:%u -> port:%u@r%u",
602 (
unsigned int)rb_ractor_id(r),
603 (
unsigned int)ractor_port_id(&rm->port),
604 (
unsigned int)rb_ractor_id(rm->port.r));
605 ccan_list_del(&rm->node);
617ractor_notify_exit(rb_execution_context_t *ec, rb_ractor_t *cr,
VALUE legacy,
bool exc)
619 RUBY_DEBUG_LOG(
"exc:%d", exc);
620 VM_ASSERT(!UNDEF_P(legacy));
621 VM_ASSERT(cr->sync.legacy ==
Qundef);
623 RACTOR_LOCK_SELF(cr);
625 ractor_free_all_ports(cr);
627 cr->sync.legacy = legacy;
628 cr->sync.legacy_exc = exc;
630 RACTOR_UNLOCK_SELF(cr);
634 VALUE token = ractor_exit_token(exc);
637 ccan_list_for_each_safe(&cr->sync.monitors, rm, nxt, node)
639 RUBY_DEBUG_LOG(
"port:%u@r%u", (
unsigned int)ractor_port_id(&rm->port), (
unsigned int)rb_ractor_id(rm->port.r));
641 ractor_try_send(ec, &rm->port, token,
false);
643 ccan_list_del(&rm->node);
647 VM_ASSERT(ccan_list_empty(&cr->sync.monitors));
653ractor_mark_ports_i(st_data_t key, st_data_t val, st_data_t data)
657 ractor_queue_mark(rq);
662ractor_sync_mark(rb_ractor_t *r)
664 rb_gc_mark(r->sync.default_port_value);
667 ractor_queue_mark(r->sync.recv_queue);
668 st_foreach(r->sync.ports, ractor_mark_ports_i, 0);
671 ractor_mark_monitors(r);
675ractor_sync_free_ports_i(st_data_t _key, st_data_t val, st_data_t _args)
679 ractor_queue_free(queue);
685ractor_sync_free(rb_ractor_t *r)
687 if (r->sync.recv_queue) {
688 ractor_queue_free(r->sync.recv_queue);
693 st_foreach(r->sync.ports, ractor_sync_free_ports_i, 0);
694 st_free_table(r->sync.ports);
695 r->sync.ports = NULL;
700ractor_sync_memsize(
const rb_ractor_t *r)
703 return st_table_size(r->sync.ports);
711ractor_sync_init(rb_ractor_t *r)
717 ccan_list_head_init(&r->sync.monitors);
720 ccan_list_head_init(&r->sync.waiters);
723 r->sync.recv_queue = ractor_queue_new();
726 r->sync.ports = st_init_numtable();
727 r->sync.default_port_value = ractor_port_new(r);
733#ifndef RUBY_THREAD_PTHREAD_H
741ractor_set_successor_once(rb_ractor_t *r, rb_ractor_t *cr)
743 if (r->sync.successor == NULL) {
744 rb_ractor_t *successor = ATOMIC_PTR_CAS(r->sync.successor, NULL, cr);
745 return successor == NULL ? cr : successor;
748 return r->sync.successor;
751static VALUE ractor_reset_belonging(
VALUE obj);
754ractor_make_remote_exception(
VALUE cause,
VALUE sender)
758 rb_ec_setup_exception(NULL, err, cause);
763ractor_value(rb_execution_context_t *ec,
VALUE self)
765 rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
766 rb_ractor_t *r = RACTOR_PTR(self);
767 rb_ractor_t *sr = ractor_set_successor_once(r, cr);
770 ractor_reset_belonging(r->sync.legacy);
772 if (r->sync.legacy_exc) {
773 rb_exc_raise(ractor_make_remote_exception(r->sync.legacy, self));
775 return r->sync.legacy;
778 rb_raise(rb_eRactorError,
"Only the successor ractor can take a value");
786ractor_prepare_payload(rb_execution_context_t *ec,
VALUE obj,
enum ractor_basket_type *ptype)
789 case basket_type_ref:
791 case basket_type_move:
792 return ractor_move(obj);
795 *ptype = basket_type_ref;
799 *ptype = basket_type_copy;
800 return ractor_copy(obj);
806ractor_basket_new(rb_execution_context_t *ec,
VALUE obj,
enum ractor_basket_type type,
bool exc)
808 VALUE v = ractor_prepare_payload(ec, obj, &type);
813 b->p.exception = exc;
821 case basket_type_ref:
823 case basket_type_copy:
824 case basket_type_move:
825 ractor_reset_belonging(b->p.v);
838 VALUE v = ractor_basket_value(b);
840 if (b->p.exception) {
841 VALUE err = ractor_make_remote_exception(v, b->sender);
842 ractor_basket_free(b);
846 ractor_basket_free(b);
852enum ractor_wakeup_status {
861 enum ractor_wakeup_status wakeup_status;
863 struct ccan_list_node node;
868ractor_waiter_included(rb_ractor_t *cr, rb_thread_t *th)
870 ASSERT_ractor_locking(cr);
874 ccan_list_for_each(&cr->sync.waiters, w, node) {
884#if USE_RUBY_DEBUG_LOG
887wakeup_status_str(
enum ractor_wakeup_status wakeup_status)
889 switch (wakeup_status) {
890 case wakeup_none:
return "none";
891 case wakeup_by_send:
return "by_send";
892 case wakeup_by_interrupt:
return "by_interrupt";
895 rb_bug(
"unreachable");
899basket_type_name(
enum ractor_basket_type type)
902 case basket_type_none:
return "none";
903 case basket_type_ref:
return "ref";
904 case basket_type_copy:
return "copy";
905 case basket_type_move:
return "move";
913#ifdef RUBY_THREAD_PTHREAD_H
920ractor_cond_wait(rb_ractor_t *r)
922#if RACTOR_CHECK_MODE > 0
923 VALUE locked_by = r->sync.locked_by;
924 r->sync.locked_by =
Qnil;
928#if RACTOR_CHECK_MODE > 0
929 r->sync.locked_by = locked_by;
934ractor_wait_no_gvl(
void *ptr)
937 rb_ractor_t *cr = waiter->th->ractor;
939 RACTOR_LOCK_SELF(cr);
941 if (waiter->wakeup_status == wakeup_none) {
942 ractor_cond_wait(cr);
945 RACTOR_UNLOCK_SELF(cr);
950rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr,
rb_unblock_function_t *ubf,
void *ptr)
956 rb_nogvl(ractor_wait_no_gvl, waiter,
964rb_ractor_sched_wakeup(rb_ractor_t *r, rb_thread_t *th)
972ractor_wakeup_all(rb_ractor_t *r,
enum ractor_wakeup_status wakeup_status)
974 ASSERT_ractor_unlocking(r);
976 RUBY_DEBUG_LOG(
"r:%u wakeup:%s", rb_ractor_id(r), wakeup_status_str(wakeup_status));
978 bool wakeup_p =
false;
985 VM_ASSERT(waiter->wakeup_status == wakeup_none);
987 waiter->wakeup_status = wakeup_status;
988 rb_ractor_sched_wakeup(r, waiter->th);
1002ubf_ractor_wait(
void *ptr)
1006 rb_thread_t *th = waiter->th;
1007 rb_ractor_t *r = th->ractor;
1010 th->unblock.func = NULL;
1011 th->unblock.arg = NULL;
1017 if (waiter->wakeup_status == wakeup_none) {
1018 RUBY_DEBUG_LOG(
"waiter:%p", (
void *)waiter);
1020 waiter->wakeup_status = wakeup_by_interrupt;
1021 ccan_list_del(&waiter->node);
1023 rb_ractor_sched_wakeup(r, waiter->th);
1031static enum ractor_wakeup_status
1032ractor_wait(rb_execution_context_t *ec, rb_ractor_t *cr)
1034 rb_thread_t *th = rb_ec_thread_ptr(ec);
1037 .wakeup_status = wakeup_none,
1041 RUBY_DEBUG_LOG(
"wait%s",
"");
1043 ASSERT_ractor_locking(cr);
1045 VM_ASSERT(GET_RACTOR() == cr);
1046 VM_ASSERT(!ractor_waiter_included(cr, th));
1048 ccan_list_add_tail(&cr->sync.waiters, &waiter.node);
1051 rb_ractor_sched_wait(ec, cr, ubf_ractor_wait, &waiter);
1053 if (waiter.wakeup_status == wakeup_none) {
1054 ccan_list_del(&waiter.node);
1057 RUBY_DEBUG_LOG(
"wakeup_status:%s", wakeup_status_str(waiter.wakeup_status));
1059 RACTOR_UNLOCK_SELF(cr);
1061 rb_ec_check_ints(ec);
1063 RACTOR_LOCK_SELF(cr);
1065 VM_ASSERT(!ractor_waiter_included(cr, th));
1066 return waiter.wakeup_status;
1070ractor_deliver_incoming_messages(rb_execution_context_t *ec, rb_ractor_t *cr)
1072 ASSERT_ractor_locking(cr);
1076 while ((b = ractor_queue_deq(cr, recv_q)) != NULL) {
1077 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
true), b);
1082ractor_check_received(rb_ractor_t *cr,
struct ractor_queue *messages)
1084 struct ractor_queue *received_queue = cr->sync.recv_queue;
1085 bool received =
false;
1087 ASSERT_ractor_locking(cr);
1089 if (ractor_queue_empty_p(cr, received_queue)) {
1090 RUBY_DEBUG_LOG(
"empty");
1096 ractor_queue_init(messages);
1097 ractor_queue_move(messages, received_queue);
1100 VM_ASSERT(ractor_queue_empty_p(cr, received_queue));
1102 RUBY_DEBUG_LOG(
"received:%d", received);
1107ractor_wait_receive(rb_execution_context_t *ec, rb_ractor_t *cr)
1110 bool deliverred =
false;
1112 RACTOR_LOCK_SELF(cr);
1114 if (ractor_check_received(cr, &messages)) {
1118 ractor_wait(ec, cr);
1121 RACTOR_UNLOCK_SELF(cr);
1124 VM_ASSERT(!ractor_queue_empty_p(cr, &messages));
1127 while ((b = ractor_queue_deq(cr, &messages)) != NULL) {
1128 ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id,
false), b);
1134ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *cr,
const struct ractor_port *rp)
1136 struct ractor_queue *rq = ractor_get_queue(cr, ractor_port_id(rp),
false);
1139 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1144 if (rq->closed && ractor_queue_empty_p(cr, rq)) {
1145 ractor_delete_port(cr, ractor_port_id(rp),
false);
1149 return ractor_basket_accept(b);
1157ractor_receive(rb_execution_context_t *ec,
const struct ractor_port *rp)
1159 rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
1160 VM_ASSERT(cr == rp->r);
1162 RUBY_DEBUG_LOG(
"port:%u", (
unsigned int)ractor_port_id(rp));
1165 VALUE v = ractor_try_receive(ec, cr, rp);
1171 ractor_wait_receive(ec, cr);
1179ractor_send_basket(rb_execution_context_t *ec,
const struct ractor_port *rp,
struct ractor_basket *b,
bool raise_on_error)
1181 bool closed =
false;
1183 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);
1187 if (ractor_closed_port_p(ec, rp->r, rp)) {
1191 b->port_id = ractor_port_id(rp);
1192 ractor_queue_enq(rp->r, rp->r->sync.recv_queue, b);
1195 RACTOR_UNLOCK(rp->r);
1200 ractor_wakeup_all(rp->r, wakeup_by_send);
1203 RUBY_DEBUG_LOG(
"closed:%u@r%u", (
unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r));
1205 if (raise_on_error) {
1206 ractor_basket_free(b);
1207 rb_raise(rb_eRactorClosedError,
"The port was already closed");
1213ractor_send0(rb_execution_context_t *ec,
const struct ractor_port *rp,
VALUE obj,
VALUE move,
bool raise_on_error)
1215 struct ractor_basket *b = ractor_basket_new(ec, obj,
RTEST(move) ? basket_type_move : basket_type_none,
false);
1216 ractor_send_basket(ec, rp, b, raise_on_error);
1218 return rp->r->pub.self;
1224 return ractor_send0(ec, rp, obj, move,
true);
1230 return ractor_send0(ec, rp, obj, move,
false);
1236 struct st_table *ports;
1241ractor_selector_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
1243 rb_gc_mark((
VALUE)key);
1249ractor_selector_mark(
void *ptr)
1254 st_foreach(s->ports, ractor_selector_mark_i, 0);
1259ractor_selector_free(
void *ptr)
1262 st_free_table(s->ports);
1267ractor_selector_memsize(
const void *ptr)
1272 size += st_memsize(s->ports);
1280 ractor_selector_mark,
1281 ractor_selector_free,
1282 ractor_selector_memsize,
1285 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1289RACTOR_SELECTOR_PTR(
VALUE selv)
1298ractor_selector_create(
VALUE klass)
1302 s->ports = st_init_numtable();
1318 if (!ractor_port_p(rpv)) {
1319 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1323 const struct ractor_port *rp = RACTOR_PORT_PTR(rpv);
1325 if (st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1326 rb_raise(rb_eArgError,
"already added");
1329 st_insert(s->ports, (st_data_t)rpv, (st_data_t)rp);
1346 if (!ractor_port_p(rpv)) {
1347 rb_raise(rb_eArgError,
"Not a Ractor::Port object");
1352 if (!st_lookup(s->ports, (st_data_t)rpv, NULL)) {
1353 rb_raise(rb_eArgError,
"not added yet");
1356 st_delete(s->ports, (st_data_t *)&rpv, NULL);
1370ractor_selector_clear(
VALUE selv)
1384ractor_selector_empty_p(
VALUE selv)
1387 return s->ports->num_entries == 0 ?
Qtrue :
Qfalse;
1394 rb_execution_context_t *ec;
1401ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t data)
1406 VALUE v = ractor_try_receive(p->ec, p->cr, rp);
1411 p->rpv = (
VALUE)key;
1420ractor_selector__wait(rb_execution_context_t *ec,
VALUE selector)
1422 rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
1432 st_foreach(s->ports, ractor_selector_wait_i, (st_data_t)&data);
1438 ractor_wait_receive(ec, cr);
1449ractor_selector_wait(
VALUE selector)
1451 return ractor_selector__wait(GET_EC(), selector);
1455ractor_selector_new(
int argc,
VALUE *ractors,
VALUE klass)
1457 VALUE selector = ractor_selector_create(klass);
1459 for (
int i=0; i<argc; i++) {
1460 ractor_selector_add(selector, ractors[i]);
1467ractor_select_internal(rb_execution_context_t *ec,
VALUE self,
VALUE ports)
1470 VALUE result = ractor_selector__wait(ec, selector);
1477#ifndef USE_RACTOR_SELECTOR
1478#define USE_RACTOR_SELECTOR 0
1481RUBY_SYMBOL_EXPORT_BEGIN
1482void rb_init_ractor_selector(
void);
1483RUBY_SYMBOL_EXPORT_END
1492rb_init_ractor_selector(
void)
1501 rb_define_method(rb_cRactorSelector,
"empty?", ractor_selector_empty_p, 0);
1506Init_RactorPort(
void)
1511 rb_define_method(rb_cRactorPort,
"initialize_copy", ractor_port_initialize_copy, 1);
1513#if USE_RACTOR_SELECTOR
1514 rb_init_ractor_selector();
#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.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
#define ALLOC
Old name of RB_ALLOC.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define ID2SYM
Old name of RB_ID2SYM.
#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.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
VALUE rb_cRactor
Ractor class.
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.
VALUE rb_ary_new_from_args(long n,...)
Constructs an array from the passed objects.
#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.
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 checking interrupts.
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...
#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 DATA_PTR(obj)
Convenient getter macro.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#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.
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.
void ruby_xfree(void *ptr)
Deallocates a storage instance.