From 5f69a7f60467fa58c2f998daffab43e118bff36c Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 9 Feb 2021 19:39:56 +1300 Subject: [PATCH] Expose scheduler as public interface & bug fixes. (#3945) * Rename `rb_scheduler` to `rb_fiber_scheduler`. * Use public interface if available. * Use `rb_check_funcall` where possible. * Don't use `unblock` unless the fiber was non-blocking. --- common.mk | 20 ++-- cont.c | 15 +-- eval.c | 8 +- ext/io/console/console.c | 7 +- ext/io/console/extconf.rb | 2 +- ext/psych/depend | 185 ++++++++++++++++++++------------- include/ruby/fiber/scheduler.h | 40 +++++++ inits.c | 2 +- internal/cont.h | 1 + internal/scheduler.h | 44 -------- io.c | 62 +++++------ process.c | 13 ++- scheduler.c | 86 +++++++-------- test/fiber/http.rb | 11 +- test/fiber/scheduler.rb | 24 ++++- test/fiber/test_thread.rb | 45 ++++++++ thread.c | 16 +-- thread_sync.c | 20 ++-- 18 files changed, 356 insertions(+), 245 deletions(-) create mode 100644 include/ruby/fiber/scheduler.h delete mode 100644 internal/scheduler.h create mode 100644 test/fiber/test_thread.rb diff --git a/common.mk b/common.mk index 810530c526..1a3de30b46 100644 --- a/common.mk +++ b/common.mk @@ -3196,13 +3196,13 @@ cont.$(OBJEXT): $(CCAN_DIR)/list/list.h cont.$(OBJEXT): $(CCAN_DIR)/str/str.h cont.$(OBJEXT): $(hdrdir)/ruby.h cont.$(OBJEXT): $(hdrdir)/ruby/ruby.h +cont.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h cont.$(OBJEXT): $(top_srcdir)/internal/array.h cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h cont.$(OBJEXT): $(top_srcdir)/internal/cont.h cont.$(OBJEXT): $(top_srcdir)/internal/gc.h cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h cont.$(OBJEXT): $(top_srcdir)/internal/proc.h -cont.$(OBJEXT): $(top_srcdir)/internal/scheduler.h cont.$(OBJEXT): $(top_srcdir)/internal/serial.h cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h cont.$(OBJEXT): $(top_srcdir)/internal/vm.h @@ -3224,6 +3224,7 @@ cont.$(OBJEXT): {$(VPATH)}cont.c cont.$(OBJEXT): {$(VPATH)}debug_counter.h cont.$(OBJEXT): {$(VPATH)}defines.h cont.$(OBJEXT): {$(VPATH)}eval_intern.h +cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h cont.$(OBJEXT): {$(VPATH)}gc.h cont.$(OBJEXT): {$(VPATH)}id.h cont.$(OBJEXT): {$(VPATH)}id_table.h @@ -5215,6 +5216,7 @@ eval.$(OBJEXT): $(CCAN_DIR)/list/list.h eval.$(OBJEXT): $(CCAN_DIR)/str/str.h eval.$(OBJEXT): $(hdrdir)/ruby.h eval.$(OBJEXT): $(hdrdir)/ruby/ruby.h +eval.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h eval.$(OBJEXT): $(top_srcdir)/internal/array.h eval.$(OBJEXT): $(top_srcdir)/internal/class.h eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h @@ -5226,7 +5228,6 @@ eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h eval.$(OBJEXT): $(top_srcdir)/internal/inits.h eval.$(OBJEXT): $(top_srcdir)/internal/io.h eval.$(OBJEXT): $(top_srcdir)/internal/object.h -eval.$(OBJEXT): $(top_srcdir)/internal/scheduler.h eval.$(OBJEXT): $(top_srcdir)/internal/serial.h eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h eval.$(OBJEXT): $(top_srcdir)/internal/string.h @@ -5254,6 +5255,7 @@ eval.$(OBJEXT): {$(VPATH)}eval.c eval.$(OBJEXT): {$(VPATH)}eval_error.c eval.$(OBJEXT): {$(VPATH)}eval_intern.h eval.$(OBJEXT): {$(VPATH)}eval_jump.c +eval.$(OBJEXT): {$(VPATH)}fiber/scheduler.h eval.$(OBJEXT): {$(VPATH)}gc.h eval.$(OBJEXT): {$(VPATH)}id.h eval.$(OBJEXT): {$(VPATH)}id_table.h @@ -6562,6 +6564,7 @@ io.$(OBJEXT): $(CCAN_DIR)/list/list.h io.$(OBJEXT): $(CCAN_DIR)/str/str.h io.$(OBJEXT): $(hdrdir)/ruby.h io.$(OBJEXT): $(hdrdir)/ruby/ruby.h +io.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h io.$(OBJEXT): $(top_srcdir)/internal/array.h io.$(OBJEXT): $(top_srcdir)/internal/bignum.h io.$(OBJEXT): $(top_srcdir)/internal/bits.h @@ -6577,7 +6580,6 @@ io.$(OBJEXT): $(top_srcdir)/internal/io.h io.$(OBJEXT): $(top_srcdir)/internal/numeric.h io.$(OBJEXT): $(top_srcdir)/internal/object.h io.$(OBJEXT): $(top_srcdir)/internal/process.h -io.$(OBJEXT): $(top_srcdir)/internal/scheduler.h io.$(OBJEXT): $(top_srcdir)/internal/serial.h io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h io.$(OBJEXT): $(top_srcdir)/internal/string.h @@ -6604,6 +6606,7 @@ io.$(OBJEXT): {$(VPATH)}defines.h io.$(OBJEXT): {$(VPATH)}dln.h io.$(OBJEXT): {$(VPATH)}encindex.h io.$(OBJEXT): {$(VPATH)}encoding.h +io.$(OBJEXT): {$(VPATH)}fiber/scheduler.h io.$(OBJEXT): {$(VPATH)}id.h io.$(OBJEXT): {$(VPATH)}id_table.h io.$(OBJEXT): {$(VPATH)}intern.h @@ -10017,6 +10020,7 @@ process.$(OBJEXT): $(CCAN_DIR)/list/list.h process.$(OBJEXT): $(CCAN_DIR)/str/str.h process.$(OBJEXT): $(hdrdir)/ruby.h process.$(OBJEXT): $(hdrdir)/ruby/ruby.h +process.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h process.$(OBJEXT): $(top_srcdir)/internal/array.h process.$(OBJEXT): $(top_srcdir)/internal/bits.h process.$(OBJEXT): $(top_srcdir)/internal/class.h @@ -10029,7 +10033,6 @@ process.$(OBJEXT): $(top_srcdir)/internal/hash.h process.$(OBJEXT): $(top_srcdir)/internal/imemo.h process.$(OBJEXT): $(top_srcdir)/internal/object.h process.$(OBJEXT): $(top_srcdir)/internal/process.h -process.$(OBJEXT): $(top_srcdir)/internal/scheduler.h process.$(OBJEXT): $(top_srcdir)/internal/serial.h process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h process.$(OBJEXT): $(top_srcdir)/internal/string.h @@ -10055,6 +10058,7 @@ process.$(OBJEXT): {$(VPATH)}debug_counter.h process.$(OBJEXT): {$(VPATH)}defines.h process.$(OBJEXT): {$(VPATH)}dln.h process.$(OBJEXT): {$(VPATH)}encoding.h +process.$(OBJEXT): {$(VPATH)}fiber/scheduler.h process.$(OBJEXT): {$(VPATH)}hrtime.h process.$(OBJEXT): {$(VPATH)}id.h process.$(OBJEXT): {$(VPATH)}id_table.h @@ -12357,11 +12361,11 @@ scheduler.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h scheduler.$(OBJEXT): $(CCAN_DIR)/list/list.h scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h scheduler.$(OBJEXT): $(hdrdir)/ruby/ruby.h +scheduler.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h scheduler.$(OBJEXT): $(top_srcdir)/internal/array.h scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h -scheduler.$(OBJEXT): $(top_srcdir)/internal/scheduler.h scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h @@ -12380,7 +12384,9 @@ scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h scheduler.$(OBJEXT): {$(VPATH)}config.h scheduler.$(OBJEXT): {$(VPATH)}defines.h scheduler.$(OBJEXT): {$(VPATH)}encoding.h +scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h scheduler.$(OBJEXT): {$(VPATH)}id.h +scheduler.$(OBJEXT): {$(VPATH)}include/ruby/fiber/scheduler.h scheduler.$(OBJEXT): {$(VPATH)}intern.h scheduler.$(OBJEXT): {$(VPATH)}internal.h scheduler.$(OBJEXT): {$(VPATH)}internal/anyargs.h @@ -12512,7 +12518,6 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/module.h scheduler.$(OBJEXT): {$(VPATH)}internal/newobj.h scheduler.$(OBJEXT): {$(VPATH)}internal/rgengc.h scheduler.$(OBJEXT): {$(VPATH)}internal/scan_args.h -scheduler.$(OBJEXT): {$(VPATH)}internal/scheduler.h scheduler.$(OBJEXT): {$(VPATH)}internal/special_consts.h scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h scheduler.$(OBJEXT): {$(VPATH)}internal/stdalign.h @@ -14034,6 +14039,7 @@ thread.$(OBJEXT): $(CCAN_DIR)/list/list.h thread.$(OBJEXT): $(CCAN_DIR)/str/str.h thread.$(OBJEXT): $(hdrdir)/ruby.h thread.$(OBJEXT): $(hdrdir)/ruby/ruby.h +thread.$(OBJEXT): $(top_srcdir)/include/ruby/fiber/scheduler.h thread.$(OBJEXT): $(top_srcdir)/internal/array.h thread.$(OBJEXT): $(top_srcdir)/internal/bits.h thread.$(OBJEXT): $(top_srcdir)/internal/class.h @@ -14046,7 +14052,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h thread.$(OBJEXT): $(top_srcdir)/internal/io.h thread.$(OBJEXT): $(top_srcdir)/internal/object.h thread.$(OBJEXT): $(top_srcdir)/internal/proc.h -thread.$(OBJEXT): $(top_srcdir)/internal/scheduler.h thread.$(OBJEXT): $(top_srcdir)/internal/serial.h thread.$(OBJEXT): $(top_srcdir)/internal/signal.h thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h @@ -14073,6 +14078,7 @@ thread.$(OBJEXT): {$(VPATH)}debug_counter.h thread.$(OBJEXT): {$(VPATH)}defines.h thread.$(OBJEXT): {$(VPATH)}encoding.h thread.$(OBJEXT): {$(VPATH)}eval_intern.h +thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h thread.$(OBJEXT): {$(VPATH)}gc.h thread.$(OBJEXT): {$(VPATH)}hrtime.h thread.$(OBJEXT): {$(VPATH)}id.h diff --git a/cont.c b/cont.c index 694c2d9632..abd6a2f46a 100644 --- a/cont.c +++ b/cont.c @@ -24,7 +24,7 @@ #include "internal/cont.h" #include "internal/proc.h" #include "internal/warnings.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #include "mjit.h" #include "vm_core.h" #include "id_table.h" @@ -1156,6 +1156,11 @@ VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber) return fiber->cont.self; } +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber) +{ + return fiber->blocking; +} + // This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new. void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber) @@ -1975,7 +1980,7 @@ rb_f_fiber(int argc, VALUE *argv, VALUE obj) static VALUE rb_fiber_scheduler(VALUE klass) { - return rb_scheduler_get(); + return rb_fiber_scheduler_get(); } /* @@ -1997,11 +2002,7 @@ rb_fiber_scheduler(VALUE klass) static VALUE rb_fiber_set_scheduler(VALUE klass, VALUE scheduler) { - // if (rb_scheduler_get() != Qnil) { - // rb_raise(rb_eFiberError, "Scheduler is already defined!"); - // } - - return rb_scheduler_set(scheduler); + return rb_fiber_scheduler_set(scheduler); } static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt); diff --git a/eval.c b/eval.c index 55d66b5508..ed8a88c52b 100644 --- a/eval.c +++ b/eval.c @@ -29,7 +29,7 @@ #include "internal/object.h" #include "internal/thread.h" #include "internal/variable.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #include "iseq.h" #include "mjit.h" #include "probes.h" @@ -147,13 +147,13 @@ ruby_options(int argc, char **argv) } static void -rb_ec_scheduler_finalize(rb_execution_context_t *ec) +rb_ec_fiber_scheduler_finalize(rb_execution_context_t *ec) { enum ruby_tag_type state; EC_PUSH_TAG(ec); if ((state = EC_EXEC_TAG()) == TAG_NONE) { - rb_scheduler_set(Qnil); + rb_fiber_scheduler_set(Qnil); } else { state = error_handle(ec, state); @@ -165,7 +165,7 @@ static void rb_ec_teardown(rb_execution_context_t *ec) { // If the user code defined a scheduler for the top level thread, run it: - rb_ec_scheduler_finalize(ec); + rb_ec_fiber_scheduler_finalize(ec); EC_PUSH_TAG(ec); if (EC_EXEC_TAG() == TAG_NONE) { diff --git a/ext/io/console/console.c b/ext/io/console/console.c index 2e2467036d..6999a3f077 100644 --- a/ext/io/console/console.c +++ b/ext/io/console/console.c @@ -80,8 +80,11 @@ static ID id_getc, id_console, id_close, id_min, id_time, id_intr; static ID id_gets, id_chomp_bang; #endif -#ifdef HAVE_RB_SCHEDULER_TIMEOUT +#if defined HAVE_RUBY_FIBER_SCHEDULER_H +# include "ruby/fiber/scheduler.h" +#elif defined HAVE_RB_SCHEDULER_TIMEOUT extern VALUE rb_scheduler_timeout(struct timeval *timeout); +# define rb_fiber_scheduler_timeout rb_scheduler_timeout #endif #define sys_fail_fptr(fptr) rb_sys_fail_str((fptr)->pathv) @@ -534,7 +537,7 @@ console_getch(int argc, VALUE *argv, VALUE io) tv.tv_sec = optp->vtime / 10; tv.tv_usec = (optp->vtime % 10) * 100000; # ifdef HAVE_RB_IO_WAIT - timeout = rb_scheduler_timeout(&tv); + timeout = rb_fiber_scheduler_make_timeout(&tv); # endif } switch (optp->vmin) { diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb index 3efdd6e092..40af8c0b72 100644 --- a/ext/io/console/extconf.rb +++ b/ext/io/console/extconf.rb @@ -24,7 +24,7 @@ when true # rb_funcallv: 2.1.0 # RARRAY_CONST_PTR: 2.1.0 # rb_sym2str: 2.2.0 - if have_func("rb_scheduler_timeout") + if have_func("rb_fiber_scheduler_make_timeout") have_func("rb_io_wait") end $defs << "-D""ENABLE_IO_GETPASS=1" diff --git a/ext/psych/depend b/ext/psych/depend index 2017319fd1..06f24f42bc 100644 --- a/ext/psych/depend +++ b/ext/psych/depend @@ -1,9 +1,48 @@ $(OBJS): $(YAML_H) # AUTOGENERATED DEPENDENCIES START +api.o: $(RUBY_EXTCONF_H) +api.o: yaml/api.c +api.o: yaml/config.h +api.o: yaml/yaml.h +api.o: yaml/yaml_private.h +dumper.o: $(RUBY_EXTCONF_H) +dumper.o: yaml/config.h +dumper.o: yaml/dumper.c +dumper.o: yaml/yaml.h +dumper.o: yaml/yaml_private.h +emitter.o: $(RUBY_EXTCONF_H) +emitter.o: yaml/config.h +emitter.o: yaml/emitter.c +emitter.o: yaml/yaml.h +emitter.o: yaml/yaml_private.h +loader.o: $(RUBY_EXTCONF_H) +loader.o: yaml/config.h +loader.o: yaml/loader.c +loader.o: yaml/yaml.h +loader.o: yaml/yaml_private.h +parser.o: $(RUBY_EXTCONF_H) +parser.o: yaml/config.h +parser.o: yaml/parser.c +parser.o: yaml/yaml.h +parser.o: yaml/yaml_private.h psych.o: $(RUBY_EXTCONF_H) psych.o: $(arch_hdrdir)/ruby/config.h psych.o: $(hdrdir)/ruby.h +psych.o: $(hdrdir)/ruby/assert.h +psych.o: $(hdrdir)/ruby/backward.h +psych.o: $(hdrdir)/ruby/backward/2/assume.h +psych.o: $(hdrdir)/ruby/backward/2/attributes.h +psych.o: $(hdrdir)/ruby/backward/2/bool.h +psych.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h +psych.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych.o: $(hdrdir)/ruby/backward/2/limits.h +psych.o: $(hdrdir)/ruby/backward/2/long_long.h +psych.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych.o: $(hdrdir)/ruby/defines.h +psych.o: $(hdrdir)/ruby/encoding.h +psych.o: $(hdrdir)/ruby/intern.h psych.o: $(hdrdir)/ruby/internal/anyargs.h psych.o: $(hdrdir)/ruby/internal/arithmetic.h psych.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -144,20 +183,6 @@ psych.o: $(hdrdir)/ruby/internal/value_type.h psych.o: $(hdrdir)/ruby/internal/variable.h psych.o: $(hdrdir)/ruby/internal/warning_push.h psych.o: $(hdrdir)/ruby/internal/xmalloc.h -psych.o: $(hdrdir)/ruby/assert.h -psych.o: $(hdrdir)/ruby/backward.h -psych.o: $(hdrdir)/ruby/backward/2/assume.h -psych.o: $(hdrdir)/ruby/backward/2/attributes.h -psych.o: $(hdrdir)/ruby/backward/2/bool.h -psych.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -psych.o: $(hdrdir)/ruby/backward/2/inttypes.h -psych.o: $(hdrdir)/ruby/backward/2/limits.h -psych.o: $(hdrdir)/ruby/backward/2/long_long.h -psych.o: $(hdrdir)/ruby/backward/2/stdalign.h -psych.o: $(hdrdir)/ruby/backward/2/stdarg.h -psych.o: $(hdrdir)/ruby/defines.h -psych.o: $(hdrdir)/ruby/encoding.h -psych.o: $(hdrdir)/ruby/intern.h psych.o: $(hdrdir)/ruby/missing.h psych.o: $(hdrdir)/ruby/onigmo.h psych.o: $(hdrdir)/ruby/oniguruma.h @@ -170,9 +195,24 @@ psych.o: psych_emitter.h psych.o: psych_parser.h psych.o: psych_to_ruby.h psych.o: psych_yaml_tree.h +psych.o: yaml/yaml.h psych_emitter.o: $(RUBY_EXTCONF_H) psych_emitter.o: $(arch_hdrdir)/ruby/config.h psych_emitter.o: $(hdrdir)/ruby.h +psych_emitter.o: $(hdrdir)/ruby/assert.h +psych_emitter.o: $(hdrdir)/ruby/backward.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/assume.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/bool.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/limits.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_emitter.o: $(hdrdir)/ruby/defines.h +psych_emitter.o: $(hdrdir)/ruby/encoding.h +psych_emitter.o: $(hdrdir)/ruby/intern.h psych_emitter.o: $(hdrdir)/ruby/internal/anyargs.h psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic.h psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -313,20 +353,6 @@ psych_emitter.o: $(hdrdir)/ruby/internal/value_type.h psych_emitter.o: $(hdrdir)/ruby/internal/variable.h psych_emitter.o: $(hdrdir)/ruby/internal/warning_push.h psych_emitter.o: $(hdrdir)/ruby/internal/xmalloc.h -psych_emitter.o: $(hdrdir)/ruby/assert.h -psych_emitter.o: $(hdrdir)/ruby/backward.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/assume.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/attributes.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/bool.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/inttypes.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/limits.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/long_long.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/stdalign.h -psych_emitter.o: $(hdrdir)/ruby/backward/2/stdarg.h -psych_emitter.o: $(hdrdir)/ruby/defines.h -psych_emitter.o: $(hdrdir)/ruby/encoding.h -psych_emitter.o: $(hdrdir)/ruby/intern.h psych_emitter.o: $(hdrdir)/ruby/missing.h psych_emitter.o: $(hdrdir)/ruby/onigmo.h psych_emitter.o: $(hdrdir)/ruby/oniguruma.h @@ -339,9 +365,24 @@ psych_emitter.o: psych_emitter.h psych_emitter.o: psych_parser.h psych_emitter.o: psych_to_ruby.h psych_emitter.o: psych_yaml_tree.h +psych_emitter.o: yaml/yaml.h psych_parser.o: $(RUBY_EXTCONF_H) psych_parser.o: $(arch_hdrdir)/ruby/config.h psych_parser.o: $(hdrdir)/ruby.h +psych_parser.o: $(hdrdir)/ruby/assert.h +psych_parser.o: $(hdrdir)/ruby/backward.h +psych_parser.o: $(hdrdir)/ruby/backward/2/assume.h +psych_parser.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/bool.h +psych_parser.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h +psych_parser.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/limits.h +psych_parser.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_parser.o: $(hdrdir)/ruby/defines.h +psych_parser.o: $(hdrdir)/ruby/encoding.h +psych_parser.o: $(hdrdir)/ruby/intern.h psych_parser.o: $(hdrdir)/ruby/internal/anyargs.h psych_parser.o: $(hdrdir)/ruby/internal/arithmetic.h psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -482,20 +523,6 @@ psych_parser.o: $(hdrdir)/ruby/internal/value_type.h psych_parser.o: $(hdrdir)/ruby/internal/variable.h psych_parser.o: $(hdrdir)/ruby/internal/warning_push.h psych_parser.o: $(hdrdir)/ruby/internal/xmalloc.h -psych_parser.o: $(hdrdir)/ruby/assert.h -psych_parser.o: $(hdrdir)/ruby/backward.h -psych_parser.o: $(hdrdir)/ruby/backward/2/assume.h -psych_parser.o: $(hdrdir)/ruby/backward/2/attributes.h -psych_parser.o: $(hdrdir)/ruby/backward/2/bool.h -psych_parser.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -psych_parser.o: $(hdrdir)/ruby/backward/2/inttypes.h -psych_parser.o: $(hdrdir)/ruby/backward/2/limits.h -psych_parser.o: $(hdrdir)/ruby/backward/2/long_long.h -psych_parser.o: $(hdrdir)/ruby/backward/2/stdalign.h -psych_parser.o: $(hdrdir)/ruby/backward/2/stdarg.h -psych_parser.o: $(hdrdir)/ruby/defines.h -psych_parser.o: $(hdrdir)/ruby/encoding.h -psych_parser.o: $(hdrdir)/ruby/intern.h psych_parser.o: $(hdrdir)/ruby/missing.h psych_parser.o: $(hdrdir)/ruby/onigmo.h psych_parser.o: $(hdrdir)/ruby/oniguruma.h @@ -508,9 +535,24 @@ psych_parser.o: psych_parser.c psych_parser.o: psych_parser.h psych_parser.o: psych_to_ruby.h psych_parser.o: psych_yaml_tree.h +psych_parser.o: yaml/yaml.h psych_to_ruby.o: $(RUBY_EXTCONF_H) psych_to_ruby.o: $(arch_hdrdir)/ruby/config.h psych_to_ruby.o: $(hdrdir)/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/assert.h +psych_to_ruby.o: $(hdrdir)/ruby/backward.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/assume.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/bool.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/limits.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_to_ruby.o: $(hdrdir)/ruby/defines.h +psych_to_ruby.o: $(hdrdir)/ruby/encoding.h +psych_to_ruby.o: $(hdrdir)/ruby/intern.h psych_to_ruby.o: $(hdrdir)/ruby/internal/anyargs.h psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic.h psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -651,20 +693,6 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/value_type.h psych_to_ruby.o: $(hdrdir)/ruby/internal/variable.h psych_to_ruby.o: $(hdrdir)/ruby/internal/warning_push.h psych_to_ruby.o: $(hdrdir)/ruby/internal/xmalloc.h -psych_to_ruby.o: $(hdrdir)/ruby/assert.h -psych_to_ruby.o: $(hdrdir)/ruby/backward.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/assume.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/attributes.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/bool.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/inttypes.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/limits.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/long_long.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdalign.h -psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdarg.h -psych_to_ruby.o: $(hdrdir)/ruby/defines.h -psych_to_ruby.o: $(hdrdir)/ruby/encoding.h -psych_to_ruby.o: $(hdrdir)/ruby/intern.h psych_to_ruby.o: $(hdrdir)/ruby/missing.h psych_to_ruby.o: $(hdrdir)/ruby/onigmo.h psych_to_ruby.o: $(hdrdir)/ruby/oniguruma.h @@ -677,9 +705,24 @@ psych_to_ruby.o: psych_parser.h psych_to_ruby.o: psych_to_ruby.c psych_to_ruby.o: psych_to_ruby.h psych_to_ruby.o: psych_yaml_tree.h +psych_to_ruby.o: yaml/yaml.h psych_yaml_tree.o: $(RUBY_EXTCONF_H) psych_yaml_tree.o: $(arch_hdrdir)/ruby/config.h psych_yaml_tree.o: $(hdrdir)/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/assert.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/assume.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/bool.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/limits.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_yaml_tree.o: $(hdrdir)/ruby/defines.h +psych_yaml_tree.o: $(hdrdir)/ruby/encoding.h +psych_yaml_tree.o: $(hdrdir)/ruby/intern.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/anyargs.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -820,20 +863,6 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/value_type.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/variable.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/warning_push.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/xmalloc.h -psych_yaml_tree.o: $(hdrdir)/ruby/assert.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/assume.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/attributes.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/bool.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/inttypes.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/limits.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/long_long.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdalign.h -psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdarg.h -psych_yaml_tree.o: $(hdrdir)/ruby/defines.h -psych_yaml_tree.o: $(hdrdir)/ruby/encoding.h -psych_yaml_tree.o: $(hdrdir)/ruby/intern.h psych_yaml_tree.o: $(hdrdir)/ruby/missing.h psych_yaml_tree.o: $(hdrdir)/ruby/onigmo.h psych_yaml_tree.o: $(hdrdir)/ruby/oniguruma.h @@ -846,4 +875,20 @@ psych_yaml_tree.o: psych_parser.h psych_yaml_tree.o: psych_to_ruby.h psych_yaml_tree.o: psych_yaml_tree.c psych_yaml_tree.o: psych_yaml_tree.h +psych_yaml_tree.o: yaml/yaml.h +reader.o: $(RUBY_EXTCONF_H) +reader.o: yaml/config.h +reader.o: yaml/reader.c +reader.o: yaml/yaml.h +reader.o: yaml/yaml_private.h +scanner.o: $(RUBY_EXTCONF_H) +scanner.o: yaml/config.h +scanner.o: yaml/scanner.c +scanner.o: yaml/yaml.h +scanner.o: yaml/yaml_private.h +writer.o: $(RUBY_EXTCONF_H) +writer.o: yaml/config.h +writer.o: yaml/writer.c +writer.o: yaml/yaml.h +writer.o: yaml/yaml_private.h # AUTOGENERATED DEPENDENCIES END diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h new file mode 100644 index 0000000000..741cc249a1 --- /dev/null +++ b/include/ruby/fiber/scheduler.h @@ -0,0 +1,40 @@ +#ifndef RUBY_FIBER_SCHEDULER_H /*-*-C-*-vi:se ft=c:*/ +#define RUBY_FIBER_SCHEDULER_H +/** + * @file + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Scheduler. + */ +#include "ruby/ruby.h" +#include "ruby/intern.h" + +VALUE rb_fiber_scheduler_get(); +VALUE rb_fiber_scheduler_set(VALUE scheduler); + +VALUE rb_fiber_scheduler_current(); +VALUE rb_fiber_scheduler_current_for_thread(VALUE thread); + +VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout); + +VALUE rb_fiber_scheduler_close(VALUE scheduler); + +VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE duration); +VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv); + +int rb_fiber_scheduler_supports_process_wait(VALUE scheduler); +VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags); + +VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout); +VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); + +VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout); +VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io); +VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io); +VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); +VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); + +#endif /* RUBY_FIBER_SCHEDULER_H */ diff --git a/inits.c b/inits.c index d2c99ed495..185f14b820 100644 --- a/inits.c +++ b/inits.c @@ -65,7 +65,7 @@ rb_call_inits(void) CALL(VM); CALL(ISeq); CALL(Thread); - CALL(Scheduler); + CALL(Fiber_Scheduler); CALL(process); CALL(Cont); CALL(Rational); diff --git a/internal/cont.h b/internal/cont.h index a365cbe978..9e49dd3c8e 100644 --- a/internal/cont.h +++ b/internal/cont.h @@ -21,5 +21,6 @@ void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE ( void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber); VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); #endif /* INTERNAL_CONT_H */ diff --git a/internal/scheduler.h b/internal/scheduler.h deleted file mode 100644 index 8314020220..0000000000 --- a/internal/scheduler.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef RUBY_SCHEDULER_H /*-*-C-*-vi:se ft=c:*/ -#define RUBY_SCHEDULER_H -/** - * @file - * @author Ruby developers - * @copyright This file is a part of the programming language Ruby. - * Permission is hereby granted, to either redistribute and/or - * modify this file, provided that the conditions mentioned in the - * file COPYING are met. Consult the file for details. - * @brief Internal header for Scheduler. - */ -#include "ruby/ruby.h" -#include "ruby/intern.h" - -VALUE rb_scheduler_get(); -VALUE rb_scheduler_set(VALUE scheduler); - -VALUE rb_scheduler_current(); -VALUE rb_thread_scheduler_current(VALUE thread); - -VALUE rb_scheduler_timeout(struct timeval *timeout); - -VALUE rb_scheduler_close(VALUE scheduler); - -VALUE rb_scheduler_kernel_sleep(VALUE scheduler, VALUE duration); -VALUE rb_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv); - -int rb_scheduler_supports_process_wait(VALUE scheduler); -VALUE rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags); - -VALUE rb_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout); -VALUE rb_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); - -VALUE rb_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout); -VALUE rb_scheduler_io_wait_readable(VALUE scheduler, VALUE io); -VALUE rb_scheduler_io_wait_writable(VALUE scheduler, VALUE io); - -int rb_scheduler_supports_io_read(VALUE scheduler); -VALUE rb_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); - -int rb_scheduler_supports_io_write(VALUE scheduler); -VALUE rb_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); - -#endif /* RUBY_SCHEDULER_H */ diff --git a/io.c b/io.c index 056bf16a2d..b4d477c038 100644 --- a/io.c +++ b/io.c @@ -13,7 +13,7 @@ #include "ruby/internal/config.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #ifdef _WIN32 # include "ruby/ruby.h" @@ -1264,10 +1264,10 @@ io_fflush(rb_io_t *fptr) VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - return rb_scheduler_io_wait(scheduler, io, events, timeout); + return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout); } rb_io_t * fptr = NULL; @@ -1306,10 +1306,10 @@ rb_io_from_fd(int fd) int rb_io_wait_readable(int f) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { return RTEST( - rb_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f)) + rb_fiber_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f)) ); } @@ -1337,10 +1337,10 @@ rb_io_wait_readable(int f) int rb_io_wait_writable(int f) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { return RTEST( - rb_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f)) + rb_fiber_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f)) ); } @@ -1377,11 +1377,11 @@ rb_io_wait_writable(int f) int rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { return RTEST( - rb_scheduler_io_wait(scheduler, rb_io_from_fd(fd), RB_INT2NUM(events), rb_scheduler_timeout(timeout)) + rb_fiber_scheduler_io_wait(scheduler, rb_io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout)) ); } @@ -1538,15 +1538,17 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) if ((n = len) <= 0) return n; - VALUE scheduler = rb_scheduler_current(); - if (scheduler != Qnil && rb_scheduler_supports_io_write(scheduler)) { - ssize_t length = RB_NUM2SSIZE( - rb_scheduler_io_write(scheduler, fptr->self, str, offset, len) - ); + VALUE scheduler = rb_fiber_scheduler_current(); + if (scheduler != Qnil) { + VALUE result = rb_fiber_scheduler_io_write(scheduler, fptr->self, str, offset, len); - if (length < 0) rb_sys_fail_path(fptr->pathv); + if (result != Qundef) { + ssize_t length = RB_NUM2SSIZE(result); - return length; + if (length < 0) rb_sys_fail_path(fptr->pathv); + + return length; + } } if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) { @@ -2623,15 +2625,17 @@ bufread_call(VALUE arg) static long io_fread(VALUE str, long offset, long size, rb_io_t *fptr) { - VALUE scheduler = rb_scheduler_current(); - if (scheduler != Qnil && rb_scheduler_supports_io_read(scheduler)) { - ssize_t length = RB_NUM2SSIZE( - rb_scheduler_io_read(scheduler, fptr->self, str, offset, size) - ); + VALUE scheduler = rb_fiber_scheduler_current(); + if (scheduler != Qnil) { + VALUE result = rb_fiber_scheduler_io_read(scheduler, fptr->self, str, offset, size); - if (length < 0) rb_sys_fail_path(fptr->pathv); + if (result != Qundef) { + ssize_t length = RB_NUM2SSIZE(result); - return length; + if (length < 0) rb_sys_fail_path(fptr->pathv); + + return length; + } } long len; @@ -11024,11 +11028,11 @@ struct wait_for_single_fd { }; static void * -rb_thread_scheduler_wait_for_single_fd(void * _args) +rb_thread_fiber_scheduler_wait_for_single_fd(void * _args) { struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args; - args->result = rb_scheduler_io_wait(args->scheduler, rb_io_from_fd(args->fd), INT2NUM(args->events), Qnil); + args->result = rb_fiber_scheduler_io_wait(args->scheduler, rb_io_from_fd(args->fd), INT2NUM(args->events), Qnil); return NULL; } @@ -11040,10 +11044,10 @@ STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT); static int nogvl_wait_for_single_fd(VALUE th, int fd, short events) { - VALUE scheduler = rb_thread_scheduler_current(th); + VALUE scheduler = rb_fiber_scheduler_current_for_thread(th); if (scheduler != Qnil) { struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events}; - rb_thread_call_with_gvl(rb_thread_scheduler_wait_for_single_fd, &args); + rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for_single_fd, &args); return RTEST(args.result); } @@ -11059,10 +11063,10 @@ nogvl_wait_for_single_fd(VALUE th, int fd, short events) static int nogvl_wait_for_single_fd(VALUE th, int fd, short events) { - VALUE scheduler = rb_thread_scheduler_current(th); + VALUE scheduler = rb_fiber_scheduler_current_for_thread(th); if (scheduler != Qnil) { struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events}; - rb_thread_call_with_gvl(rb_thread_scheduler_wait_for_single_fd, &args); + rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for_single_fd, &args); return RTEST(args.result); } diff --git a/process.c b/process.c index 674f05dd6c..0f29a6dd52 100644 --- a/process.c +++ b/process.c @@ -13,7 +13,7 @@ #include "ruby/internal/config.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #include "coroutine/Stack.h" #include @@ -1345,10 +1345,9 @@ rb_process_status_wait(rb_pid_t pid, int flags) { // We only enter the scheduler if we are "blocking": if (!(flags & WNOHANG)) { - VALUE scheduler = rb_scheduler_current(); - if (rb_scheduler_supports_process_wait(scheduler)) { - return rb_scheduler_process_wait(scheduler, pid, flags); - } + VALUE scheduler = rb_fiber_scheduler_current(); + VALUE result = rb_fiber_scheduler_process_wait(scheduler, pid, flags); + if (result != Qundef) return result; } COROUTINE_STACK_LOCAL(struct waitpid_state, w); @@ -5104,10 +5103,10 @@ static VALUE rb_f_sleep(int argc, VALUE *argv, VALUE _) { time_t beg = time(0); - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - rb_scheduler_kernel_sleepv(scheduler, argc, argv); + rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv); } else { if (argc == 0) { diff --git a/scheduler.c b/scheduler.c index 88db433f1e..4687231abf 100644 --- a/scheduler.c +++ b/scheduler.c @@ -9,7 +9,7 @@ **********************************************************************/ #include "vm_core.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #include "ruby/io.h" static ID id_close; @@ -25,7 +25,7 @@ static ID id_io_write; static ID id_io_wait; void -Init_Scheduler(void) +Init_Fiber_Scheduler(void) { id_close = rb_intern_const("close"); @@ -41,7 +41,7 @@ Init_Scheduler(void) } VALUE -rb_scheduler_get(void) +rb_fiber_scheduler_get(void) { rb_thread_t *thread = GET_THREAD(); VM_ASSERT(thread); @@ -50,14 +50,14 @@ rb_scheduler_get(void) } VALUE -rb_scheduler_set(VALUE scheduler) +rb_fiber_scheduler_set(VALUE scheduler) { rb_thread_t *thread = GET_THREAD(); VM_ASSERT(thread); // We invoke Scheduler#close when setting it to something else, to ensure the previous scheduler runs to completion before changing the scheduler. That way, we do not need to consider interactions, e.g., of a Fiber from the previous scheduler with the new scheduler. if (thread->scheduler != Qnil) { - rb_scheduler_close(thread->scheduler); + rb_fiber_scheduler_close(thread->scheduler); } thread->scheduler = scheduler; @@ -66,7 +66,7 @@ rb_scheduler_set(VALUE scheduler) } static VALUE -rb_threadptr_scheduler_current(rb_thread_t *thread) +rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread) { VM_ASSERT(thread); @@ -78,18 +78,18 @@ rb_threadptr_scheduler_current(rb_thread_t *thread) } VALUE -rb_scheduler_current(void) +rb_fiber_scheduler_current(void) { - return rb_threadptr_scheduler_current(GET_THREAD()); + return rb_fiber_scheduler_current_for_threadptr(GET_THREAD()); } -VALUE rb_thread_scheduler_current(VALUE thread) +VALUE rb_fiber_scheduler_current_for_thread(VALUE thread) { - return rb_threadptr_scheduler_current(rb_thread_ptr(thread)); + return rb_fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread)); } VALUE -rb_scheduler_close(VALUE scheduler) +rb_fiber_scheduler_close(VALUE scheduler) { if (rb_respond_to(scheduler, id_close)) { return rb_funcall(scheduler, id_close, 0); @@ -99,7 +99,7 @@ rb_scheduler_close(VALUE scheduler) } VALUE -rb_scheduler_timeout(struct timeval *timeout) +rb_fiber_scheduler_make_timeout(struct timeval *timeout) { if (timeout) { return rb_float_new((double)timeout->tv_sec + (0.000001f * timeout->tv_usec)); @@ -109,80 +109,74 @@ rb_scheduler_timeout(struct timeval *timeout) } VALUE -rb_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout) +rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout) { return rb_funcall(scheduler, id_kernel_sleep, 1, timeout); } VALUE -rb_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv) +rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv) { return rb_funcallv(scheduler, id_kernel_sleep, argc, argv); } -int -rb_scheduler_supports_process_wait(VALUE scheduler) +VALUE +rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags) { - return rb_respond_to(scheduler, id_process_wait); + VALUE arguments[] = { + PIDT2NUM(pid), RB_INT2NUM(flags) + }; + + return rb_check_funcall(scheduler, id_process_wait, 2, arguments); } VALUE -rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags) -{ - return rb_funcall(scheduler, id_process_wait, 2, PIDT2NUM(pid), RB_INT2NUM(flags)); -} - -VALUE -rb_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout) +rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout) { return rb_funcall(scheduler, id_block, 2, blocker, timeout); } VALUE -rb_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber) +rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber) { return rb_funcall(scheduler, id_unblock, 2, blocker, fiber); } VALUE -rb_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout) +rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout) { return rb_funcall(scheduler, id_io_wait, 3, io, events, timeout); } VALUE -rb_scheduler_io_wait_readable(VALUE scheduler, VALUE io) +rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io) { - return rb_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_READABLE), Qnil); + return rb_fiber_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_READABLE), Qnil); } VALUE -rb_scheduler_io_wait_writable(VALUE scheduler, VALUE io) +rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io) { - return rb_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_WRITABLE), Qnil); -} - -int -rb_scheduler_supports_io_read(VALUE scheduler) -{ - return rb_respond_to(scheduler, id_io_read); + return rb_fiber_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_WRITABLE), Qnil); } VALUE -rb_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length) +rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length) { - return rb_funcall(scheduler, id_io_read, 4, io, buffer, SIZET2NUM(offset), SIZET2NUM(length)); -} - -int -rb_scheduler_supports_io_write(VALUE scheduler) -{ - return rb_respond_to(scheduler, id_io_write); + VALUE arguments[] = { + io, buffer, SIZET2NUM(offset), SIZET2NUM(length) + }; + + return rb_check_funcall(scheduler, id_io_read, 4, arguments); } VALUE -rb_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length) +rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length) { + VALUE arguments[] = { + io, buffer, SIZET2NUM(offset), SIZET2NUM(length) + }; + // We should ensure string has capacity to receive data, and then resize it afterwards. - return rb_funcall(scheduler, id_io_write, 4, io, buffer, SIZET2NUM(offset), SIZET2NUM(length)); + return rb_check_funcall(scheduler, id_io_write, 4, arguments); } diff --git a/test/fiber/http.rb b/test/fiber/http.rb index ad51ae3c76..53a4602bd4 100644 --- a/test/fiber/http.rb +++ b/test/fiber/http.rb @@ -15,24 +15,25 @@ def fetch_topics(topics) topics.each do |topic| Fiber.new(blocking: Fiber.current.blocking?) do uri = URI("https://www.google.com/search?q=#{topic}") - responses[topic] = Net::HTTP.get(uri).scan(topic).size + response = Net::HTTP.get(uri) + responses[topic] = response.scan(topic).size end.resume end - Thread.fiber_scheduler&.run + Fiber.scheduler&.run return responses end def sweep(repeats: 3, **options) times = (1..8).map do |i| - $stderr.puts "Measuring #{i} topic(s)..." + $stderr.puts "Measuring #{i} topic(s) #{options.inspect}..." topics = TOPICS[0...i] Thread.new do Benchmark.realtime do scheduler = Scheduler.new - Fiber.set_scheduler scheduler + Fiber.set_scheduler(scheduler) repeats.times do Fiber.new(**options) do @@ -49,5 +50,5 @@ def sweep(repeats: 3, **options) puts JSON.dump(times.map{|value| value.round(3)}) end -sweep(blocking: true) +# sweep(blocking: true) sweep(blocking: false) diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb index b3c3eaff59..f2fb304e19 100644 --- a/test/fiber/scheduler.rb +++ b/test/fiber/scheduler.rb @@ -47,6 +47,8 @@ class Scheduler end def run + # $stderr.puts [__method__, Fiber.current].inspect + while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive? # Can only handle file descriptors up to 1024... readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout) @@ -54,9 +56,11 @@ class Scheduler # puts "readable: #{readable}" if readable&.any? # puts "writable: #{writable}" if writable&.any? + selected = {} + readable&.each do |io| if fiber = @readable.delete(io) - fiber.resume + selected[fiber] = IO::READABLE elsif io == @urgent.first @urgent.first.read_nonblock(1024) end @@ -64,10 +68,14 @@ class Scheduler writable&.each do |io| if fiber = @writable.delete(io) - fiber.resume + selected[fiber] |= IO::WRITABLE end end + selected.each do |fiber, events| + fiber.resume(events) + end + if @waiting.any? time = current_time waiting, @waiting = @waiting, {} @@ -96,6 +104,8 @@ class Scheduler end def close + # $stderr.puts [__method__, Fiber.current].inspect + raise "Scheduler already closed!" if @closed self.run @@ -118,6 +128,8 @@ class Scheduler end def process_wait(pid, flags) + # $stderr.puts [__method__, pid, flags, Fiber.current].inspect + # This is a very simple way to implement a non-blocking wait: Thread.new do Process::Status.wait(pid, flags) @@ -125,6 +137,8 @@ class Scheduler end def io_wait(io, events, duration) + # $stderr.puts [__method__, io, events, duration, Fiber.current].inspect + unless (events & IO::READABLE).zero? @readable[io] = Fiber.current end @@ -134,12 +148,12 @@ class Scheduler end Fiber.yield - - return true end # Used for Kernel#sleep and Mutex#sleep def kernel_sleep(duration = nil) + # $stderr.puts [__method__, duration, Fiber.current].inspect + self.block(:sleep, duration) return true @@ -171,6 +185,8 @@ class Scheduler # This might be called from another thread. def unblock(blocker, fiber) # $stderr.puts [__method__, blocker, fiber].inspect + # $stderr.puts blocker.backtrace.inspect + # $stderr.puts fiber.backtrace.inspect @lock.synchronize do @ready << fiber diff --git a/test/fiber/test_thread.rb b/test/fiber/test_thread.rb new file mode 100644 index 0000000000..5fc80f0e6c --- /dev/null +++ b/test/fiber/test_thread.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true +require "test/unit" +require_relative 'scheduler' + +class TestFiberThread < Test::Unit::TestCase + def test_thread_join + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + result = nil + Fiber.schedule do + result = Thread.new{:done}.value + end + + scheduler.run + result + end + + assert_equal :done, thread.value + end + + def test_thread_join_blocking + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + result = nil + Fiber.schedule do + Fiber.new(blocking: true) do + # This can deadlock if the blocking state is not taken into account: + Thread.new do + sleep(0) + result = :done + end.join + end.resume + end + + scheduler.run + result + end + + assert_equal :done, thread.value + end +end diff --git a/thread.c b/thread.c index e3689487ce..1e35ad4e1c 100644 --- a/thread.c +++ b/thread.c @@ -81,7 +81,7 @@ #include "internal/io.h" #include "internal/object.h" #include "internal/proc.h" -#include "internal/scheduler.h" +#include "ruby/fiber/scheduler.h" #include "internal/signal.h" #include "internal/thread.h" #include "internal/time.h" @@ -551,8 +551,8 @@ rb_threadptr_join_list_wakeup(rb_thread_t *thread) while (join_list) { rb_thread_t *target_thread = join_list->thread; - if (target_thread->scheduler != Qnil) { - rb_scheduler_unblock(target_thread->scheduler, target_thread->self, rb_fiberptr_self(join_list->fiber)); + if (target_thread->scheduler != Qnil && rb_fiberptr_blocking(join_list->fiber) == 0) { + rb_fiber_scheduler_unblock(target_thread->scheduler, target_thread->self, rb_fiberptr_self(join_list->fiber)); } else { rb_threadptr_interrupt(target_thread); @@ -772,7 +772,7 @@ thread_do_start(rb_thread_t *th) rb_bug("unreachable"); } - rb_scheduler_set(Qnil); + rb_fiber_scheduler_set(Qnil); } void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec); @@ -1178,10 +1178,10 @@ thread_join_sleep(VALUE arg) } while (target_th->status != THREAD_KILLED) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - rb_scheduler_block(scheduler, target_th->self, p->timeout); + rb_fiber_scheduler_block(scheduler, target_th->self, p->timeout); } else if (!limit) { th->status = THREAD_STOPPED_FOREVER; rb_ractor_sleeper_threads_inc(th->ractor); @@ -1525,9 +1525,9 @@ rb_thread_sleep_interruptible(void) static void rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - rb_scheduler_block(scheduler, blocker, Qnil); + rb_fiber_scheduler_block(scheduler, blocker, Qnil); } else { thread_debug("rb_thread_sleep_deadly_allow_spurious_wakeup\n"); sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE); diff --git a/thread_sync.c b/thread_sync.c index 8295b3d8c2..9932abde11 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -32,8 +32,8 @@ sync_wakeup(struct list_head *head, long max) if (cur->th->status != THREAD_KILLED) { - if (cur->th->scheduler != Qnil) { - rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); + if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) { + rb_fiber_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); } else { rb_threadptr_interrupt(cur->th); cur->th->status = THREAD_RUNNABLE; @@ -267,8 +267,8 @@ mutex_owned_p(rb_fiber_t *fiber, rb_mutex_t *mutex) } } -static VALUE call_rb_scheduler_block(VALUE mutex) { - return rb_scheduler_block(rb_scheduler_current(), mutex, Qnil); +static VALUE call_rb_fiber_scheduler_block(VALUE mutex) { + return rb_fiber_scheduler_block(rb_fiber_scheduler_current(), mutex, Qnil); } static VALUE @@ -302,7 +302,7 @@ do_mutex_lock(VALUE self, int interruptible_p) } while (mutex->fiber != fiber) { - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { COROUTINE_STACK_LOCAL(struct sync_waiter, w); w->self = self; @@ -311,7 +311,7 @@ do_mutex_lock(VALUE self, int interruptible_p) list_add_tail(&mutex->waitq, &w->node); - rb_ensure(call_rb_scheduler_block, self, delete_from_waitq, (VALUE)w); + rb_ensure(call_rb_fiber_scheduler_block, self, delete_from_waitq, (VALUE)w); if (!mutex->fiber) { mutex->fiber = fiber; @@ -437,8 +437,8 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber) list_for_each_safe(&mutex->waitq, cur, next, node) { list_del_init(&cur->node); - if (cur->th->scheduler != Qnil) { - rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); + if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) { + rb_fiber_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); goto found; } else { switch (cur->th->status) { @@ -545,9 +545,9 @@ rb_mutex_sleep(VALUE self, VALUE timeout) rb_mutex_unlock(self); time_t beg = time(0); - VALUE scheduler = rb_scheduler_current(); + VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - rb_scheduler_kernel_sleep(scheduler, timeout); + rb_fiber_scheduler_kernel_sleep(scheduler, timeout); mutex_lock_uninterruptible(self); } else { if (NIL_P(timeout)) {