[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
This commit is contained in:
Nobuyoshi Nakada 2024-08-31 16:17:13 +09:00 коммит произвёл git
Родитель 5dbb67a593
Коммит 4a1ea9b63a
2 изменённых файлов: 70 добавлений и 7 удалений

Просмотреть файл

@ -81,7 +81,7 @@ getattr(int fd, conmode *t)
#define CSI "\x1b\x5b" #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; static ID id_gets, id_flush, id_chomp_bang;
#if defined HAVE_RUBY_FIBER_SCHEDULER_H #if defined HAVE_RUBY_FIBER_SCHEDULER_H
@ -1566,6 +1566,56 @@ rb_io_closed_p(VALUE io)
} }
#endif #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: * call-seq:
* IO.console -> #<File:/dev/tty> * IO.console -> #<File:/dev/tty>
@ -1594,10 +1644,9 @@ console_dev(int argc, VALUE *argv, VALUE klass)
// Force the class to be File. // Force the class to be File.
if (klass == rb_cIO) klass = rb_cFile; if (klass == rb_cIO) klass = rb_cFile;
if (rb_const_defined(klass, id_console)) { if (console_dev_get(klass, &con)) {
con = rb_const_get(klass, id_console);
if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(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; con = 0;
} }
} }
@ -1606,7 +1655,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
if (sym == ID2SYM(id_close) && argc == 1) { if (sym == ID2SYM(id_close) && argc == 1) {
if (con) { if (con) {
rb_io_close(con); rb_io_close(con);
rb_const_remove(klass, id_console); console_dev_remove(klass);
con = 0; con = 0;
} }
return Qnil; return Qnil;
@ -1647,7 +1696,7 @@ console_dev(int argc, VALUE *argv, VALUE klass)
#ifdef CONSOLE_DEVICE_FOR_WRITING #ifdef CONSOLE_DEVICE_FOR_WRITING
rb_io_set_write_io(con, out); rb_io_set_write_io(con, out);
#endif #endif
rb_const_set(klass, id_console, con); console_dev_set(klass, con);
} }
if (sym) { if (sym) {
@ -1769,11 +1818,15 @@ Init_console(void)
#endif #endif
#undef rb_intern #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_getc = rb_intern("getc");
id_gets = rb_intern("gets"); id_gets = rb_intern("gets");
id_flush = rb_intern("flush"); id_flush = rb_intern("flush");
id_chomp_bang = rb_intern("chomp!"); id_chomp_bang = rb_intern("chomp!");
id_console = rb_intern("console");
id_close = rb_intern("close"); id_close = rb_intern("close");
#define init_rawmode_opt_id(name) \ #define init_rawmode_opt_id(name) \
rawmode_opt_ids[kwd_##name] = rb_intern(#name) rawmode_opt_ids[kwd_##name] = rb_intern(#name)

Просмотреть файл

@ -20,5 +20,15 @@ class TestIOConsoleInRactor < Test::Unit::TestCase
end end
puts r.take puts r.take
end; 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
end if defined? Ractor end if defined? Ractor