diff options
| author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2024-08-31 16:17:13 +0900 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2024-08-31 08:43:59 +0000 |
| commit | 4a1ea9b63ae24918e7aaddcb41de5dbe0f500d7f (patch) | |
| tree | 9e705b1eec52fd9c3b11ad4073fd10576456fac2 | |
| parent | 5dbb67a5938579feb506b4ca59c0a39963681588 (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.c | 67 | ||||
| -rw-r--r-- | test/io/console/test_ractor.rb | 10 |
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 |
