summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2024-08-31 16:17:13 +0900
committergit <svn-admin@ruby-lang.org>2024-08-31 08:43:59 +0000
commit4a1ea9b63ae24918e7aaddcb41de5dbe0f500d7f (patch)
tree9e705b1eec52fd9c3b11ad4073fd10576456fac2
parent5dbb67a5938579feb506b4ca59c0a39963681588 (diff)
[ruby/io-console] Store console IO in Ractor-local storage
Ractor requires a shareable class has shareable constants only, but IO is not shareable unless frozen. https://github.com/ruby/io-console/commit/65e0ff895c
-rw-r--r--ext/io/console/console.c67
-rw-r--r--test/io/console/test_ractor.rb10
2 files changed, 70 insertions, 7 deletions
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 489869894e..91e12d9ff7 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -81,7 +81,7 @@ getattr(int fd, conmode *t)
#define CSI "\x1b\x5b"
-static ID id_getc, id_console, id_close;
+static ID id_getc, id_close;
static ID id_gets, id_flush, id_chomp_bang;
#if defined HAVE_RUBY_FIBER_SCHEDULER_H
@@ -1566,6 +1566,56 @@ rb_io_closed_p(VALUE io)
}
#endif
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+#include "ruby/ractor.h"
+static rb_ractor_local_key_t key_console_dev;
+
+static bool
+console_dev_get(VALUE klass, VALUE *dev)
+{
+ return rb_ractor_local_storage_value_lookup(key_console_dev, dev);
+}
+
+static void
+console_dev_set(VALUE klass, VALUE value)
+{
+ rb_ractor_local_storage_value_set(key_console_dev, value);
+}
+
+static void
+console_dev_remove(VALUE klass)
+{
+ console_dev_set(klass, Qnil);
+}
+
+#else
+
+static ID id_console;
+
+static bool
+console_dev_get(VALUE klass, VALUE *dev)
+{
+ if (rb_const_defined(klass, id_console)) {
+ *dev = rb_const_get(klass, id_console);
+ return true;
+ }
+ return false;
+}
+
+static void
+console_dev_set(VALUE klass, VALUE value)
+{
+ rb_const_set(klass, id_console, value);
+}
+
+static void
+console_dev_remove(VALUE klass)
+{
+ rb_const_remove(klass, id_console);
+}
+
+#endif
+
/*
* call-seq:
* IO.console -> #<File:/dev/tty>
@@ -1594,10 +1644,9 @@ console_dev(int argc, VALUE *argv, VALUE klass)
// Force the class to be File.
if (klass == rb_cIO) klass = rb_cFile;
- if (rb_const_defined(klass, id_console)) {
- con = rb_const_get(klass, id_console);
+ if (console_dev_get(klass, &con)) {
if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
- rb_const_remove(klass, id_console);
+ console_dev_remove(klass);
con = 0;
}
}
@@ -1606,7 +1655,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
if (sym == ID2SYM(id_close) && argc == 1) {
if (con) {
rb_io_close(con);
- rb_const_remove(klass, id_console);
+ console_dev_remove(klass);
con = 0;
}
return Qnil;
@@ -1647,7 +1696,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
#ifdef CONSOLE_DEVICE_FOR_WRITING
rb_io_set_write_io(con, out);
#endif
- rb_const_set(klass, id_console, con);
+ console_dev_set(klass, con);
}
if (sym) {
@@ -1769,11 +1818,15 @@ Init_console(void)
#endif
#undef rb_intern
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ key_console_dev = rb_ractor_local_storage_value_newkey();
+#else
+ id_console = rb_intern("console");
+#endif
id_getc = rb_intern("getc");
id_gets = rb_intern("gets");
id_flush = rb_intern("flush");
id_chomp_bang = rb_intern("chomp!");
- id_console = rb_intern("console");
id_close = rb_intern("close");
#define init_rawmode_opt_id(name) \
rawmode_opt_ids[kwd_##name] = rb_intern(#name)
diff --git a/test/io/console/test_ractor.rb b/test/io/console/test_ractor.rb
index 0bbd39cdee..b30988f47e 100644
--- a/test/io/console/test_ractor.rb
+++ b/test/io/console/test_ractor.rb
@@ -20,5 +20,15 @@ class TestIOConsoleInRactor < Test::Unit::TestCase
end
puts r.take
end;
+
+ assert_in_out_err(%W[-r#{path}], "#{<<~"begin;"}\n#{<<~'end;'}", ["true"], [])
+ begin;
+ console = IO.console
+ $VERBOSE = nil
+ r = Ractor.new do
+ IO.console
+ end
+ puts console.class == r.take.class
+ end;
end
end if defined? Ractor