diff --git a/README.ja.md b/README.ja.md index 278285dc83db3c..9bbc3a83a5fdee 100644 --- a/README.ja.md +++ b/README.ja.md @@ -4,6 +4,8 @@ [![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master) [![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby) +[English](rdoc-ref:README.md) + # Rubyとは Rubyはシンプルかつ強力なオブジェクト指向スクリプト言語です. Rubyは純粋なオブジェクト指向言語として設計されているので, diff --git a/README.md b/README.md index 5ed312cca872a0..02435b419e026d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows") [![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby) +[日本語](rdoc-ref:README.ja.md) + # What is Ruby? Ruby is an interpreted object-oriented programming language often diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 271abb3c84006a..7d09ac52838f66 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -2413,3 +2413,39 @@ def call_test(obj) :ok end RUBY + +# When creating bmethods in Ractors, they should only be usable from their +# defining ractor, even if it is GC'd +assert_equal 'ok', <<~'RUBY' +CLASSES = 1000.times.map { Class.new }.freeze + +# This would be better to run in parallel, but there's a bug with lambda +# creation and YJIT causing crashes in dev mode +ractors = CLASSES.map do |klass| + Ractor.new(klass) do |klass| + Ractor.receive + klass.define_method(:foo) {} + end +end + +ractors.each do |ractor| + ractor << nil + ractor.join +end + +ractors.clear +GC.start + +any = 1000.times.map do + Ractor.new do + CLASSES.any? do |klass| + begin + klass.new.foo + true + rescue RuntimeError + false + end + end + end +end.map(&:value).none? && :ok +RUBY diff --git a/class.c b/class.c index 0cec526b74fe98..9716ba07dae2e2 100644 --- a/class.c +++ b/class.c @@ -734,8 +734,10 @@ class_detach_subclasses(VALUE klass, VALUE arg) static void class_switch_superclass(VALUE super, VALUE klass) { - class_detach_subclasses(klass, Qnil); - rb_class_subclass_add(super, klass); + RB_VM_LOCKING() { + class_detach_subclasses(klass, Qnil); + rb_class_subclass_add(super, klass); + } } /** diff --git a/method.h b/method.h index 87fb2498a054d7..b174c6fccb4d94 100644 --- a/method.h +++ b/method.h @@ -167,7 +167,7 @@ typedef struct rb_method_refined_struct { typedef struct rb_method_bmethod_struct { VALUE proc; /* should be marked */ struct rb_hook_list_struct *hooks; - VALUE defined_ractor; + rb_serial_t defined_ractor_id; } rb_method_bmethod_t; enum method_optimized_type { diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 96cd7be4720a66..fad1d4ce3266d4 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -38,6 +38,7 @@ require_relative "support/matchers" require_relative "support/permissions" require_relative "support/platforms" +require_relative "support/windows_tag_group" $debug = false @@ -56,6 +57,7 @@ def self.ruby=(ruby) config.include Spec::Path config.include Spec::Platforms config.include Spec::Permissions + config.include Spec::WindowsTagGroup # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" @@ -129,4 +131,19 @@ def self.ruby=(ruby) ensure reset! end + + Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.each do |tag, file_paths| + file_pattern = Regexp.union(file_paths.map {|path| Regexp.new(Regexp.escape(path) + "$") }) + + config.define_derived_metadata(file_path: file_pattern) do |metadata| + metadata[tag] = true + end + end + + config.before(:context) do |example| + metadata = example.class.metadata + if metadata[:type] != :aruba && metadata.keys.none? {|k| Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.keys.include?(k) } + warn "#{metadata[:file_path]} is not assigned to any Windows runner group. see spec/support/windows_tag_group.rb for details." + end + end end diff --git a/spec/bundler/support/windows_tag_group.rb b/spec/bundler/support/windows_tag_group.rb new file mode 100644 index 00000000000000..8eb0a749dafbaf --- /dev/null +++ b/spec/bundler/support/windows_tag_group.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +# This group classifies test files into 4 groups by running `bin/rspec --profile 10000` +# to ensure balanced execution times. When adding new test files, it is recommended to +# re-aggregate and adjust the groups to keep them balanced. +# For now, please add new files to group 'windows_d'. + +module Spec + module WindowsTagGroup + EXAMPLE_MAPPINGS = { + windows_a: [ + "spec/runtime/setup_spec.rb", + "spec/commands/install_spec.rb", + "spec/commands/add_spec.rb", + "spec/install/gems/compact_index_spec.rb", + "spec/commands/config_spec.rb", + "spec/commands/pristine_spec.rb", + "spec/install/gemfile/path_spec.rb", + "spec/update/git_spec.rb", + "spec/commands/open_spec.rb", + "spec/commands/remove_spec.rb", + "spec/commands/show_spec.rb", + "spec/plugins/source/example_spec.rb", + "spec/commands/console_spec.rb", + "spec/runtime/require_spec.rb", + "spec/runtime/env_helpers_spec.rb", + "spec/runtime/gem_tasks_spec.rb", + "spec/install/gemfile_spec.rb", + "spec/commands/fund_spec.rb", + "spec/commands/init_spec.rb", + "spec/bundler/ruby_dsl_spec.rb", + "spec/bundler/mirror_spec.rb", + "spec/bundler/source/git/git_proxy_spec.rb", + "spec/bundler/source_list_spec.rb", + "spec/bundler/plugin/installer_spec.rb", + "spec/bundler/friendly_errors_spec.rb", + "spec/resolver/platform_spec.rb", + "spec/bundler/fetcher/downloader_spec.rb", + "spec/update/force_spec.rb", + "spec/bundler/env_spec.rb", + "spec/install/gems/mirror_spec.rb", + "spec/install/failure_spec.rb", + "spec/bundler/yaml_serializer_spec.rb", + "spec/bundler/environment_preserver_spec.rb", + "spec/install/gemfile/install_if_spec.rb", + "spec/install/gems/gemfile_source_header_spec.rb", + "spec/bundler/fetcher/base_spec.rb", + "spec/bundler/rubygems_integration_spec.rb", + "spec/bundler/worker_spec.rb", + "spec/bundler/dependency_spec.rb", + "spec/bundler/ui_spec.rb", + "spec/bundler/plugin/source_list_spec.rb", + "spec/bundler/source/path_spec.rb", + ], + windows_b: [ + "spec/install/gemfile/git_spec.rb", + "spec/install/gems/standalone_spec.rb", + "spec/commands/lock_spec.rb", + "spec/cache/gems_spec.rb", + "spec/other/major_deprecation_spec.rb", + "spec/install/gems/dependency_api_spec.rb", + "spec/install/gemfile/gemspec_spec.rb", + "spec/plugins/install_spec.rb", + "spec/commands/binstubs_spec.rb", + "spec/install/gems/flex_spec.rb", + "spec/runtime/inline_spec.rb", + "spec/commands/post_bundle_message_spec.rb", + "spec/runtime/executable_spec.rb", + "spec/lock/git_spec.rb", + "spec/plugins/hook_spec.rb", + "spec/install/allow_offline_install_spec.rb", + "spec/install/gems/post_install_spec.rb", + "spec/install/gemfile/ruby_spec.rb", + "spec/install/security_policy_spec.rb", + "spec/install/yanked_spec.rb", + "spec/update/gemfile_spec.rb", + "spec/runtime/load_spec.rb", + "spec/plugins/command_spec.rb", + "spec/commands/version_spec.rb", + "spec/install/prereleases_spec.rb", + "spec/bundler/uri_credentials_filter_spec.rb", + "spec/bundler/plugin_spec.rb", + "spec/install/gems/mirror_probe_spec.rb", + "spec/plugins/list_spec.rb", + "spec/bundler/compact_index_client/parser_spec.rb", + "spec/bundler/gem_version_promoter_spec.rb", + "spec/other/cli_dispatch_spec.rb", + "spec/bundler/source/rubygems_spec.rb", + "spec/cache/platform_spec.rb", + "spec/update/gems/fund_spec.rb", + "spec/bundler/stub_specification_spec.rb", + "spec/bundler/retry_spec.rb", + "spec/bundler/installer/spec_installation_spec.rb", + "spec/bundler/spec_set_spec.rb", + "spec/quality_es_spec.rb", + "spec/bundler/index_spec.rb", + "spec/other/cli_man_pages_spec.rb", + ], + windows_c: [ + "spec/commands/newgem_spec.rb", + "spec/commands/exec_spec.rb", + "spec/commands/clean_spec.rb", + "spec/commands/platform_spec.rb", + "spec/cache/git_spec.rb", + "spec/install/gemfile/groups_spec.rb", + "spec/commands/cache_spec.rb", + "spec/commands/check_spec.rb", + "spec/commands/list_spec.rb", + "spec/install/path_spec.rb", + "spec/bundler/cli_spec.rb", + "spec/install/bundler_spec.rb", + "spec/install/git_spec.rb", + "spec/commands/doctor_spec.rb", + "spec/bundler/dsl_spec.rb", + "spec/install/gems/fund_spec.rb", + "spec/install/gems/env_spec.rb", + "spec/bundler/ruby_version_spec.rb", + "spec/bundler/definition_spec.rb", + "spec/install/gemfile/eval_gemfile_spec.rb", + "spec/plugins/source_spec.rb", + "spec/install/gems/dependency_api_fallback_spec.rb", + "spec/plugins/uninstall_spec.rb", + "spec/bundler/plugin/index_spec.rb", + "spec/bundler/bundler_spec.rb", + "spec/bundler/fetcher_spec.rb", + "spec/bundler/source/rubygems/remote_spec.rb", + "spec/bundler/lockfile_parser_spec.rb", + "spec/cache/cache_path_spec.rb", + "spec/bundler/source/git_spec.rb", + "spec/bundler/source_spec.rb", + "spec/commands/ssl_spec.rb", + "spec/bundler/fetcher/compact_index_spec.rb", + "spec/bundler/plugin/api_spec.rb", + "spec/bundler/endpoint_specification_spec.rb", + "spec/bundler/fetcher/index_spec.rb", + "spec/bundler/settings/validator_spec.rb", + "spec/bundler/build_metadata_spec.rb", + "spec/bundler/current_ruby_spec.rb", + "spec/bundler/installer/gem_installer_spec.rb", + "spec/bundler/cli_common_spec.rb", + "spec/bundler/ci_detector_spec.rb", + ], + windows_d: [ + "spec/commands/outdated_spec.rb", + "spec/commands/update_spec.rb", + "spec/lock/lockfile_spec.rb", + "spec/install/deploy_spec.rb", + "spec/install/gemfile/sources_spec.rb", + "spec/runtime/self_management_spec.rb", + "spec/install/gemfile/specific_platform_spec.rb", + "spec/commands/info_spec.rb", + "spec/install/gems/resolving_spec.rb", + "spec/install/gemfile/platform_spec.rb", + "spec/bundler/gem_helper_spec.rb", + "spec/install/global_cache_spec.rb", + "spec/runtime/platform_spec.rb", + "spec/update/gems/post_install_spec.rb", + "spec/install/gems/native_extensions_spec.rb", + "spec/install/force_spec.rb", + "spec/cache/path_spec.rb", + "spec/install/gemspecs_spec.rb", + "spec/commands/help_spec.rb", + "spec/bundler/shared_helpers_spec.rb", + "spec/bundler/settings_spec.rb", + "spec/resolver/basic_spec.rb", + "spec/install/gemfile/force_ruby_platform_spec.rb", + "spec/commands/licenses_spec.rb", + "spec/install/gemfile/lockfile_spec.rb", + "spec/bundler/fetcher/dependency_spec.rb", + "spec/quality_spec.rb", + "spec/bundler/remote_specification_spec.rb", + "spec/install/process_lock_spec.rb", + "spec/install/binstubs_spec.rb", + "spec/bundler/compact_index_client/updater_spec.rb", + "spec/bundler/ui/shell_spec.rb", + "spec/other/ext_spec.rb", + "spec/commands/issue_spec.rb", + "spec/update/path_spec.rb", + "spec/bundler/plugin/api/source_spec.rb", + "spec/install/gems/win32_spec.rb", + "spec/bundler/plugin/dsl_spec.rb", + "spec/runtime/requiring_spec.rb", + "spec/bundler/plugin/events_spec.rb", + "spec/bundler/resolver/candidate_spec.rb", + "spec/bundler/digest_spec.rb", + "spec/bundler/fetcher/gem_remote_fetcher_spec.rb", + ], + }.freeze + end +end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index 10b7655e9a5562..1faecd0cb25e13 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -917,4 +917,17 @@ class T end end; end + + def test_safe_multi_ractor_subclasses_list_mutation + assert_ractor "#{<<~"begin;"}\n#{<<~'end;'}" + begin; + 4.times.map do + Ractor.new do + 20_000.times do + Object.new.singleton_class + end + end + end.each(&:join) + end; + end end diff --git a/thread_pthread.c b/thread_pthread.c index 2eaa407f10ca94..93b32e55c0f72b 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1122,8 +1122,10 @@ thread_sched_to_waiting_until_wakeup(struct rb_thread_sched *sched, rb_thread_t { if (!RUBY_VM_INTERRUPTED(th->ec)) { bool can_direct_transfer = !th_has_dedicated_nt(th); + th->status = THREAD_STOPPED_FOREVER; thread_sched_wakeup_next_thread(sched, th, can_direct_transfer); thread_sched_wait_running_turn(sched, th, can_direct_transfer); + th->status = THREAD_RUNNABLE; } else { RUBY_DEBUG_LOG("th:%u interrupted", rb_th_serial(th)); @@ -1149,6 +1151,7 @@ thread_sched_yield(struct rb_thread_sched *sched, rb_thread_t *th) bool can_direct_transfer = !th_has_dedicated_nt(th); thread_sched_to_ready_common(sched, th, false, can_direct_transfer); thread_sched_wait_running_turn(sched, th, can_direct_transfer); + th->status = THREAD_RUNNABLE; } else { VM_ASSERT(sched->readyq_cnt == 0); @@ -1338,7 +1341,7 @@ void rb_ractor_lock_self(rb_ractor_t *r); void rb_ractor_unlock_self(rb_ractor_t *r); // The current thread for a ractor is put to "sleep" (descheduled in the STOPPED_FOREVER state) waiting for -// a ractor action to wake it up. See docs for `ractor_sched_sleep_with_cleanup` for more info. +// a ractor action to wake it up. void rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf, void *ubf_arg) { @@ -2868,7 +2871,7 @@ static struct { static void timer_thread_check_timeslice(rb_vm_t *vm); static int timer_thread_set_timeout(rb_vm_t *vm); -static void timer_thread_wakeup_thread(rb_thread_t *th); +static void timer_thread_wakeup_thread(rb_thread_t *th, uint32_t event_serial); #include "thread_pthread_mn.c" @@ -2970,7 +2973,7 @@ timer_thread_check_exceed(rb_hrtime_t abs, rb_hrtime_t now) } static rb_thread_t * -timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now) +timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now, uint32_t *event_serial) { struct rb_thread_sched_waiting *w = ccan_list_top(&timer_th.waiting, struct rb_thread_sched_waiting, node); @@ -2987,32 +2990,31 @@ timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now) w->flags = thread_sched_waiting_none; w->data.result = 0; - return thread_sched_waiting_thread(w); + rb_thread_t *th = thread_sched_waiting_thread(w); + *event_serial = w->data.event_serial; + return th; } return NULL; } static void -timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th) +timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th, uint32_t event_serial) { - if (sched->running != th) { + if (sched->running != th && th->event_serial == event_serial) { thread_sched_to_ready_common(sched, th, true, false); } - else { - // will be release the execution right - } } static void -timer_thread_wakeup_thread(rb_thread_t *th) +timer_thread_wakeup_thread(rb_thread_t *th, uint32_t event_serial) { RUBY_DEBUG_LOG("th:%u", rb_th_serial(th)); struct rb_thread_sched *sched = TH_SCHED(th); thread_sched_lock(sched, th); { - timer_thread_wakeup_thread_locked(sched, th); + timer_thread_wakeup_thread_locked(sched, th, event_serial); } thread_sched_unlock(sched, th); } @@ -3022,11 +3024,14 @@ timer_thread_check_timeout(rb_vm_t *vm) { rb_hrtime_t now = rb_hrtime_now(); rb_thread_t *th; + uint32_t event_serial; rb_native_mutex_lock(&timer_th.waiting_lock); { - while ((th = timer_thread_deq_wakeup(vm, now)) != NULL) { - timer_thread_wakeup_thread(th); + while ((th = timer_thread_deq_wakeup(vm, now, &event_serial)) != NULL) { + rb_native_mutex_unlock(&timer_th.waiting_lock); + timer_thread_wakeup_thread(th, event_serial); + rb_native_mutex_lock(&timer_th.waiting_lock); } } rb_native_mutex_unlock(&timer_th.waiting_lock); diff --git a/thread_pthread.h b/thread_pthread.h index d635948c4bbb7c..f579e53781a74c 100644 --- a/thread_pthread.h +++ b/thread_pthread.h @@ -39,6 +39,7 @@ struct rb_thread_sched_waiting { #else uint64_t timeout; #endif + uint32_t event_serial; int fd; // -1 for timeout only int result; } data; diff --git a/thread_pthread_mn.c b/thread_pthread_mn.c index 8100fd534e461e..2211d4d1067c39 100644 --- a/thread_pthread_mn.c +++ b/thread_pthread_mn.c @@ -3,7 +3,7 @@ #if USE_MN_THREADS static void timer_thread_unregister_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags); -static void timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th); +static void timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th, uint32_t event_serial); static bool timer_thread_cancel_waiting(rb_thread_t *th) @@ -15,9 +15,7 @@ timer_thread_cancel_waiting(rb_thread_t *th) if (th->sched.waiting_reason.flags) { canceled = true; ccan_list_del_init(&th->sched.waiting_reason.node); - if (th->sched.waiting_reason.flags & (thread_sched_waiting_io_read | thread_sched_waiting_io_write)) { - timer_thread_unregister_waiting(th, th->sched.waiting_reason.data.fd, th->sched.waiting_reason.flags); - } + timer_thread_unregister_waiting(th, th->sched.waiting_reason.data.fd, th->sched.waiting_reason.flags); th->sched.waiting_reason.flags = thread_sched_waiting_none; } } @@ -57,7 +55,7 @@ ubf_event_waiting(void *ptr) thread_sched_unlock(sched, th); } -static bool timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel); +static bool timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel, uint32_t event_serial); // return true if timed out static bool @@ -67,13 +65,15 @@ thread_sched_wait_events(struct rb_thread_sched *sched, rb_thread_t *th, int fd, volatile bool timedout = false, need_cancel = false; + uint32_t event_serial = ++th->event_serial; // overflow is okay + if (ubf_set(th, ubf_event_waiting, (void *)th)) { return false; } thread_sched_lock(sched, th); { - if (timer_thread_register_waiting(th, fd, events, rel)) { + if (timer_thread_register_waiting(th, fd, events, rel, event_serial)) { RUBY_DEBUG_LOG("wait fd:%d", fd); RB_VM_SAVE_MACHINE_CONTEXT(th); @@ -81,9 +81,11 @@ thread_sched_wait_events(struct rb_thread_sched *sched, rb_thread_t *th, int fd, RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th); if (th->sched.waiting_reason.flags == thread_sched_waiting_none) { - // already awaken + th->event_serial++; + // timer thread has dequeued us already, but it won't try to wake us because we bumped our serial } else if (RUBY_VM_INTERRUPTED(th->ec)) { + th->event_serial++; // make sure timer thread doesn't try to wake us need_cancel = true; } else { @@ -111,7 +113,8 @@ thread_sched_wait_events(struct rb_thread_sched *sched, rb_thread_t *th, int fd, } thread_sched_unlock(sched, th); - ubf_clear(th); // TODO: maybe it is already NULL? + // if ubf triggered between sched unlock and ubf clear, sched->running == th here + ubf_clear(th); VM_ASSERT(sched->running == th); @@ -680,7 +683,7 @@ kqueue_already_registered(int fd) // return false if the fd is not waitable or not need to wait. static bool -timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel) +timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel, uint32_t event_serial) { RUBY_DEBUG_LOG("th:%u fd:%d flag:%d rel:%lu", rb_th_serial(th), fd, flags, rel ? (unsigned long)*rel : 0); @@ -807,6 +810,7 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting th->sched.waiting_reason.data.timeout = abs; th->sched.waiting_reason.data.fd = fd; th->sched.waiting_reason.data.result = 0; + th->sched.waiting_reason.data.event_serial = event_serial; } if (abs == 0) { // no timeout @@ -855,6 +859,10 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting static void timer_thread_unregister_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags) { + if (!(th->sched.waiting_reason.flags & (thread_sched_waiting_io_read | thread_sched_waiting_io_write))) { + return; + } + RUBY_DEBUG_LOG("th:%u fd:%d", rb_th_serial(th), fd); #if HAVE_SYS_EVENT_H kqueue_unregister_waiting(fd, flags); @@ -885,7 +893,7 @@ timer_thread_setup_mn(void) #endif RUBY_DEBUG_LOG("comm_fds:%d/%d", timer_th.comm_fds[0], timer_th.comm_fds[1]); - timer_thread_register_waiting(NULL, timer_th.comm_fds[0], thread_sched_waiting_io_read | thread_sched_waiting_io_force, NULL); + timer_thread_register_waiting(NULL, timer_th.comm_fds[0], thread_sched_waiting_io_read | thread_sched_waiting_io_force, NULL, 0); } static int @@ -986,8 +994,9 @@ timer_thread_polling(rb_vm_t *vm) th->sched.waiting_reason.flags = thread_sched_waiting_none; th->sched.waiting_reason.data.fd = -1; th->sched.waiting_reason.data.result = filter; + uint32_t event_serial = th->sched.waiting_reason.data.event_serial; - timer_thread_wakeup_thread_locked(sched, th); + timer_thread_wakeup_thread_locked(sched, th, event_serial); } else { // already released @@ -1031,8 +1040,9 @@ timer_thread_polling(rb_vm_t *vm) th->sched.waiting_reason.flags = thread_sched_waiting_none; th->sched.waiting_reason.data.fd = -1; th->sched.waiting_reason.data.result = (int)events; + uint32_t event_serial = th->sched.waiting_reason.data.event_serial; - timer_thread_wakeup_thread_locked(sched, th); + timer_thread_wakeup_thread_locked(sched, th, event_serial); } else { // already released diff --git a/vm_core.h b/vm_core.h index 9d11457966ed71..09f27f6e859fd1 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1127,6 +1127,7 @@ typedef struct rb_thread_struct { struct rb_thread_sched_item sched; bool mn_schedulable; rb_atomic_t serial; // only for RUBY_DEBUG_LOG() + uint32_t event_serial; VALUE last_status; /* $? */ diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 60e1b647ae5d8d..8c1992de43d495 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -4121,7 +4121,7 @@ vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling VALUE procv = cme->def->body.bmethod.proc; if (!RB_OBJ_SHAREABLE_P(procv) && - cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) { + cme->def->body.bmethod.defined_ractor_id != rb_ractor_id(rb_ec_ractor_ptr(ec))) { rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor"); } @@ -4144,7 +4144,7 @@ vm_call_iseq_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct VALUE procv = cme->def->body.bmethod.proc; if (!RB_OBJ_SHAREABLE_P(procv) && - cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) { + cme->def->body.bmethod.defined_ractor_id != rb_ractor_id(rb_ec_ractor_ptr(ec))) { rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor"); } diff --git a/vm_method.c b/vm_method.c index 179deb749daeec..c4f391b5afe38a 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1020,7 +1020,7 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de } case VM_METHOD_TYPE_BMETHOD: RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts); - RB_OBJ_WRITE(me, &def->body.bmethod.defined_ractor, rb_ractor_self(GET_RACTOR())); + def->body.bmethod.defined_ractor_id = rb_ractor_id(rb_ec_ractor_ptr(GET_EC())); return; case VM_METHOD_TYPE_NOTIMPLEMENTED: setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), (VALUE(*)(ANYARGS))rb_f_notimplement_internal, -1); @@ -1060,7 +1060,6 @@ method_definition_reset(const rb_method_entry_t *me) break; case VM_METHOD_TYPE_BMETHOD: RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc); - RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.defined_ractor); /* give up to check all in a list */ if (def->body.bmethod.hooks) rb_gc_writebarrier_remember((VALUE)me); break;