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.
This commit is contained in:
Samuel Williams 2021-02-09 19:39:56 +13:00 коммит произвёл GitHub
Родитель 3c593f28ed
Коммит 5f69a7f604
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 356 добавлений и 245 удалений

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

@ -3196,13 +3196,13 @@ cont.$(OBJEXT): $(CCAN_DIR)/list/list.h
cont.$(OBJEXT): $(CCAN_DIR)/str/str.h cont.$(OBJEXT): $(CCAN_DIR)/str/str.h
cont.$(OBJEXT): $(hdrdir)/ruby.h cont.$(OBJEXT): $(hdrdir)/ruby.h
cont.$(OBJEXT): $(hdrdir)/ruby/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/array.h
cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h
cont.$(OBJEXT): $(top_srcdir)/internal/cont.h cont.$(OBJEXT): $(top_srcdir)/internal/cont.h
cont.$(OBJEXT): $(top_srcdir)/internal/gc.h cont.$(OBJEXT): $(top_srcdir)/internal/gc.h
cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h
cont.$(OBJEXT): $(top_srcdir)/internal/proc.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/serial.h
cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
cont.$(OBJEXT): $(top_srcdir)/internal/vm.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)}debug_counter.h
cont.$(OBJEXT): {$(VPATH)}defines.h cont.$(OBJEXT): {$(VPATH)}defines.h
cont.$(OBJEXT): {$(VPATH)}eval_intern.h cont.$(OBJEXT): {$(VPATH)}eval_intern.h
cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
cont.$(OBJEXT): {$(VPATH)}gc.h cont.$(OBJEXT): {$(VPATH)}gc.h
cont.$(OBJEXT): {$(VPATH)}id.h cont.$(OBJEXT): {$(VPATH)}id.h
cont.$(OBJEXT): {$(VPATH)}id_table.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): $(CCAN_DIR)/str/str.h
eval.$(OBJEXT): $(hdrdir)/ruby.h eval.$(OBJEXT): $(hdrdir)/ruby.h
eval.$(OBJEXT): $(hdrdir)/ruby/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/array.h
eval.$(OBJEXT): $(top_srcdir)/internal/class.h eval.$(OBJEXT): $(top_srcdir)/internal/class.h
eval.$(OBJEXT): $(top_srcdir)/internal/compilers.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/inits.h
eval.$(OBJEXT): $(top_srcdir)/internal/io.h eval.$(OBJEXT): $(top_srcdir)/internal/io.h
eval.$(OBJEXT): $(top_srcdir)/internal/object.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/serial.h
eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
eval.$(OBJEXT): $(top_srcdir)/internal/string.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_error.c
eval.$(OBJEXT): {$(VPATH)}eval_intern.h eval.$(OBJEXT): {$(VPATH)}eval_intern.h
eval.$(OBJEXT): {$(VPATH)}eval_jump.c eval.$(OBJEXT): {$(VPATH)}eval_jump.c
eval.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
eval.$(OBJEXT): {$(VPATH)}gc.h eval.$(OBJEXT): {$(VPATH)}gc.h
eval.$(OBJEXT): {$(VPATH)}id.h eval.$(OBJEXT): {$(VPATH)}id.h
eval.$(OBJEXT): {$(VPATH)}id_table.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): $(CCAN_DIR)/str/str.h
io.$(OBJEXT): $(hdrdir)/ruby.h io.$(OBJEXT): $(hdrdir)/ruby.h
io.$(OBJEXT): $(hdrdir)/ruby/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/array.h
io.$(OBJEXT): $(top_srcdir)/internal/bignum.h io.$(OBJEXT): $(top_srcdir)/internal/bignum.h
io.$(OBJEXT): $(top_srcdir)/internal/bits.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/numeric.h
io.$(OBJEXT): $(top_srcdir)/internal/object.h io.$(OBJEXT): $(top_srcdir)/internal/object.h
io.$(OBJEXT): $(top_srcdir)/internal/process.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/serial.h
io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
io.$(OBJEXT): $(top_srcdir)/internal/string.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)}dln.h
io.$(OBJEXT): {$(VPATH)}encindex.h io.$(OBJEXT): {$(VPATH)}encindex.h
io.$(OBJEXT): {$(VPATH)}encoding.h io.$(OBJEXT): {$(VPATH)}encoding.h
io.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
io.$(OBJEXT): {$(VPATH)}id.h io.$(OBJEXT): {$(VPATH)}id.h
io.$(OBJEXT): {$(VPATH)}id_table.h io.$(OBJEXT): {$(VPATH)}id_table.h
io.$(OBJEXT): {$(VPATH)}intern.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): $(CCAN_DIR)/str/str.h
process.$(OBJEXT): $(hdrdir)/ruby.h process.$(OBJEXT): $(hdrdir)/ruby.h
process.$(OBJEXT): $(hdrdir)/ruby/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/array.h
process.$(OBJEXT): $(top_srcdir)/internal/bits.h process.$(OBJEXT): $(top_srcdir)/internal/bits.h
process.$(OBJEXT): $(top_srcdir)/internal/class.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/imemo.h
process.$(OBJEXT): $(top_srcdir)/internal/object.h process.$(OBJEXT): $(top_srcdir)/internal/object.h
process.$(OBJEXT): $(top_srcdir)/internal/process.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/serial.h
process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
process.$(OBJEXT): $(top_srcdir)/internal/string.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)}defines.h
process.$(OBJEXT): {$(VPATH)}dln.h process.$(OBJEXT): {$(VPATH)}dln.h
process.$(OBJEXT): {$(VPATH)}encoding.h process.$(OBJEXT): {$(VPATH)}encoding.h
process.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
process.$(OBJEXT): {$(VPATH)}hrtime.h process.$(OBJEXT): {$(VPATH)}hrtime.h
process.$(OBJEXT): {$(VPATH)}id.h process.$(OBJEXT): {$(VPATH)}id.h
process.$(OBJEXT): {$(VPATH)}id_table.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)/list/list.h
scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h
scheduler.$(OBJEXT): $(hdrdir)/ruby/ruby.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/array.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.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/serial.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.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)}config.h
scheduler.$(OBJEXT): {$(VPATH)}defines.h scheduler.$(OBJEXT): {$(VPATH)}defines.h
scheduler.$(OBJEXT): {$(VPATH)}encoding.h scheduler.$(OBJEXT): {$(VPATH)}encoding.h
scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
scheduler.$(OBJEXT): {$(VPATH)}id.h scheduler.$(OBJEXT): {$(VPATH)}id.h
scheduler.$(OBJEXT): {$(VPATH)}include/ruby/fiber/scheduler.h
scheduler.$(OBJEXT): {$(VPATH)}intern.h scheduler.$(OBJEXT): {$(VPATH)}intern.h
scheduler.$(OBJEXT): {$(VPATH)}internal.h scheduler.$(OBJEXT): {$(VPATH)}internal.h
scheduler.$(OBJEXT): {$(VPATH)}internal/anyargs.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/newobj.h
scheduler.$(OBJEXT): {$(VPATH)}internal/rgengc.h scheduler.$(OBJEXT): {$(VPATH)}internal/rgengc.h
scheduler.$(OBJEXT): {$(VPATH)}internal/scan_args.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/special_consts.h
scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h
scheduler.$(OBJEXT): {$(VPATH)}internal/stdalign.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): $(CCAN_DIR)/str/str.h
thread.$(OBJEXT): $(hdrdir)/ruby.h thread.$(OBJEXT): $(hdrdir)/ruby.h
thread.$(OBJEXT): $(hdrdir)/ruby/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/array.h
thread.$(OBJEXT): $(top_srcdir)/internal/bits.h thread.$(OBJEXT): $(top_srcdir)/internal/bits.h
thread.$(OBJEXT): $(top_srcdir)/internal/class.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/io.h
thread.$(OBJEXT): $(top_srcdir)/internal/object.h thread.$(OBJEXT): $(top_srcdir)/internal/object.h
thread.$(OBJEXT): $(top_srcdir)/internal/proc.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/serial.h
thread.$(OBJEXT): $(top_srcdir)/internal/signal.h thread.$(OBJEXT): $(top_srcdir)/internal/signal.h
thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.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)}defines.h
thread.$(OBJEXT): {$(VPATH)}encoding.h thread.$(OBJEXT): {$(VPATH)}encoding.h
thread.$(OBJEXT): {$(VPATH)}eval_intern.h thread.$(OBJEXT): {$(VPATH)}eval_intern.h
thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
thread.$(OBJEXT): {$(VPATH)}gc.h thread.$(OBJEXT): {$(VPATH)}gc.h
thread.$(OBJEXT): {$(VPATH)}hrtime.h thread.$(OBJEXT): {$(VPATH)}hrtime.h
thread.$(OBJEXT): {$(VPATH)}id.h thread.$(OBJEXT): {$(VPATH)}id.h

15
cont.c
Просмотреть файл

@ -24,7 +24,7 @@
#include "internal/cont.h" #include "internal/cont.h"
#include "internal/proc.h" #include "internal/proc.h"
#include "internal/warnings.h" #include "internal/warnings.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#include "mjit.h" #include "mjit.h"
#include "vm_core.h" #include "vm_core.h"
#include "id_table.h" #include "id_table.h"
@ -1156,6 +1156,11 @@ VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber)
return fiber->cont.self; 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. // This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new.
void void
rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber) 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 static VALUE
rb_fiber_scheduler(VALUE klass) 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 static VALUE
rb_fiber_set_scheduler(VALUE klass, VALUE scheduler) rb_fiber_set_scheduler(VALUE klass, VALUE scheduler)
{ {
// if (rb_scheduler_get() != Qnil) { return rb_fiber_scheduler_set(scheduler);
// rb_raise(rb_eFiberError, "Scheduler is already defined!");
// }
return rb_scheduler_set(scheduler);
} }
static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt); static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt);

8
eval.c
Просмотреть файл

@ -29,7 +29,7 @@
#include "internal/object.h" #include "internal/object.h"
#include "internal/thread.h" #include "internal/thread.h"
#include "internal/variable.h" #include "internal/variable.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#include "iseq.h" #include "iseq.h"
#include "mjit.h" #include "mjit.h"
#include "probes.h" #include "probes.h"
@ -147,13 +147,13 @@ ruby_options(int argc, char **argv)
} }
static void 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; enum ruby_tag_type state;
EC_PUSH_TAG(ec); EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) { if ((state = EC_EXEC_TAG()) == TAG_NONE) {
rb_scheduler_set(Qnil); rb_fiber_scheduler_set(Qnil);
} }
else { else {
state = error_handle(ec, state); state = error_handle(ec, state);
@ -165,7 +165,7 @@ static void
rb_ec_teardown(rb_execution_context_t *ec) rb_ec_teardown(rb_execution_context_t *ec)
{ {
// If the user code defined a scheduler for the top level thread, run it: // 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); EC_PUSH_TAG(ec);
if (EC_EXEC_TAG() == TAG_NONE) { if (EC_EXEC_TAG() == TAG_NONE) {

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

@ -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; static ID id_gets, id_chomp_bang;
#endif #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); extern VALUE rb_scheduler_timeout(struct timeval *timeout);
# define rb_fiber_scheduler_timeout rb_scheduler_timeout
#endif #endif
#define sys_fail_fptr(fptr) rb_sys_fail_str((fptr)->pathv) #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_sec = optp->vtime / 10;
tv.tv_usec = (optp->vtime % 10) * 100000; tv.tv_usec = (optp->vtime % 10) * 100000;
# ifdef HAVE_RB_IO_WAIT # ifdef HAVE_RB_IO_WAIT
timeout = rb_scheduler_timeout(&tv); timeout = rb_fiber_scheduler_make_timeout(&tv);
# endif # endif
} }
switch (optp->vmin) { switch (optp->vmin) {

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

@ -24,7 +24,7 @@ when true
# rb_funcallv: 2.1.0 # rb_funcallv: 2.1.0
# RARRAY_CONST_PTR: 2.1.0 # RARRAY_CONST_PTR: 2.1.0
# rb_sym2str: 2.2.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") have_func("rb_io_wait")
end end
$defs << "-D""ENABLE_IO_GETPASS=1" $defs << "-D""ENABLE_IO_GETPASS=1"

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

@ -1,9 +1,48 @@
$(OBJS): $(YAML_H) $(OBJS): $(YAML_H)
# AUTOGENERATED DEPENDENCIES START # 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: $(RUBY_EXTCONF_H)
psych.o: $(arch_hdrdir)/ruby/config.h psych.o: $(arch_hdrdir)/ruby/config.h
psych.o: $(hdrdir)/ruby.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/anyargs.h
psych.o: $(hdrdir)/ruby/internal/arithmetic.h psych.o: $(hdrdir)/ruby/internal/arithmetic.h
psych.o: $(hdrdir)/ruby/internal/arithmetic/char.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/variable.h
psych.o: $(hdrdir)/ruby/internal/warning_push.h psych.o: $(hdrdir)/ruby/internal/warning_push.h
psych.o: $(hdrdir)/ruby/internal/xmalloc.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/missing.h
psych.o: $(hdrdir)/ruby/onigmo.h psych.o: $(hdrdir)/ruby/onigmo.h
psych.o: $(hdrdir)/ruby/oniguruma.h psych.o: $(hdrdir)/ruby/oniguruma.h
@ -170,9 +195,24 @@ psych.o: psych_emitter.h
psych.o: psych_parser.h psych.o: psych_parser.h
psych.o: psych_to_ruby.h psych.o: psych_to_ruby.h
psych.o: psych_yaml_tree.h psych.o: psych_yaml_tree.h
psych.o: yaml/yaml.h
psych_emitter.o: $(RUBY_EXTCONF_H) psych_emitter.o: $(RUBY_EXTCONF_H)
psych_emitter.o: $(arch_hdrdir)/ruby/config.h psych_emitter.o: $(arch_hdrdir)/ruby/config.h
psych_emitter.o: $(hdrdir)/ruby.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/anyargs.h
psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic.h psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic.h
psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/char.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/variable.h
psych_emitter.o: $(hdrdir)/ruby/internal/warning_push.h psych_emitter.o: $(hdrdir)/ruby/internal/warning_push.h
psych_emitter.o: $(hdrdir)/ruby/internal/xmalloc.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/missing.h
psych_emitter.o: $(hdrdir)/ruby/onigmo.h psych_emitter.o: $(hdrdir)/ruby/onigmo.h
psych_emitter.o: $(hdrdir)/ruby/oniguruma.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_parser.h
psych_emitter.o: psych_to_ruby.h psych_emitter.o: psych_to_ruby.h
psych_emitter.o: psych_yaml_tree.h psych_emitter.o: psych_yaml_tree.h
psych_emitter.o: yaml/yaml.h
psych_parser.o: $(RUBY_EXTCONF_H) psych_parser.o: $(RUBY_EXTCONF_H)
psych_parser.o: $(arch_hdrdir)/ruby/config.h psych_parser.o: $(arch_hdrdir)/ruby/config.h
psych_parser.o: $(hdrdir)/ruby.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/anyargs.h
psych_parser.o: $(hdrdir)/ruby/internal/arithmetic.h psych_parser.o: $(hdrdir)/ruby/internal/arithmetic.h
psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/char.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/variable.h
psych_parser.o: $(hdrdir)/ruby/internal/warning_push.h psych_parser.o: $(hdrdir)/ruby/internal/warning_push.h
psych_parser.o: $(hdrdir)/ruby/internal/xmalloc.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/missing.h
psych_parser.o: $(hdrdir)/ruby/onigmo.h psych_parser.o: $(hdrdir)/ruby/onigmo.h
psych_parser.o: $(hdrdir)/ruby/oniguruma.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_parser.h
psych_parser.o: psych_to_ruby.h psych_parser.o: psych_to_ruby.h
psych_parser.o: psych_yaml_tree.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: $(RUBY_EXTCONF_H)
psych_to_ruby.o: $(arch_hdrdir)/ruby/config.h psych_to_ruby.o: $(arch_hdrdir)/ruby/config.h
psych_to_ruby.o: $(hdrdir)/ruby.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/anyargs.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic.h psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/char.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/variable.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/warning_push.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/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/missing.h
psych_to_ruby.o: $(hdrdir)/ruby/onigmo.h psych_to_ruby.o: $(hdrdir)/ruby/onigmo.h
psych_to_ruby.o: $(hdrdir)/ruby/oniguruma.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.c
psych_to_ruby.o: psych_to_ruby.h psych_to_ruby.o: psych_to_ruby.h
psych_to_ruby.o: psych_yaml_tree.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: $(RUBY_EXTCONF_H)
psych_yaml_tree.o: $(arch_hdrdir)/ruby/config.h psych_yaml_tree.o: $(arch_hdrdir)/ruby/config.h
psych_yaml_tree.o: $(hdrdir)/ruby.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/anyargs.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic.h psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/char.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/variable.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/warning_push.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/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/missing.h
psych_yaml_tree.o: $(hdrdir)/ruby/onigmo.h psych_yaml_tree.o: $(hdrdir)/ruby/onigmo.h
psych_yaml_tree.o: $(hdrdir)/ruby/oniguruma.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_to_ruby.h
psych_yaml_tree.o: psych_yaml_tree.c psych_yaml_tree.o: psych_yaml_tree.c
psych_yaml_tree.o: psych_yaml_tree.h 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 # AUTOGENERATED DEPENDENCIES END

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

@ -0,0 +1,40 @@
#ifndef RUBY_FIBER_SCHEDULER_H /*-*-C-*-vi:se ft=c:*/
#define RUBY_FIBER_SCHEDULER_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @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 */

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

@ -65,7 +65,7 @@ rb_call_inits(void)
CALL(VM); CALL(VM);
CALL(ISeq); CALL(ISeq);
CALL(Thread); CALL(Thread);
CALL(Scheduler); CALL(Fiber_Scheduler);
CALL(process); CALL(process);
CALL(Cont); CALL(Cont);
CALL(Rational); CALL(Rational);

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

@ -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); void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber);
VALUE rb_fiberptr_self(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 */ #endif /* INTERNAL_CONT_H */

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

@ -1,44 +0,0 @@
#ifndef RUBY_SCHEDULER_H /*-*-C-*-vi:se ft=c:*/
#define RUBY_SCHEDULER_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @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 */

62
io.c
Просмотреть файл

@ -13,7 +13,7 @@
#include "ruby/internal/config.h" #include "ruby/internal/config.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#ifdef _WIN32 #ifdef _WIN32
# include "ruby/ruby.h" # include "ruby/ruby.h"
@ -1264,10 +1264,10 @@ io_fflush(rb_io_t *fptr)
VALUE VALUE
rb_io_wait(VALUE io, VALUE events, VALUE timeout) rb_io_wait(VALUE io, VALUE events, VALUE timeout)
{ {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { 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; rb_io_t * fptr = NULL;
@ -1306,10 +1306,10 @@ rb_io_from_fd(int fd)
int int
rb_io_wait_readable(int f) rb_io_wait_readable(int f)
{ {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
return RTEST( 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 int
rb_io_wait_writable(int f) rb_io_wait_writable(int f)
{ {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
return RTEST( 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 int
rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) 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) { if (scheduler != Qnil) {
return RTEST( 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; if ((n = len) <= 0) return n;
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil && rb_scheduler_supports_io_write(scheduler)) { if (scheduler != Qnil) {
ssize_t length = RB_NUM2SSIZE( VALUE result = rb_fiber_scheduler_io_write(scheduler, fptr->self, str, offset, len);
rb_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))) { if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
@ -2623,15 +2625,17 @@ bufread_call(VALUE arg)
static long static long
io_fread(VALUE str, long offset, long size, rb_io_t *fptr) io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
{ {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil && rb_scheduler_supports_io_read(scheduler)) { if (scheduler != Qnil) {
ssize_t length = RB_NUM2SSIZE( VALUE result = rb_fiber_scheduler_io_read(scheduler, fptr->self, str, offset, size);
rb_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; long len;
@ -11024,11 +11028,11 @@ struct wait_for_single_fd {
}; };
static void * 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; 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; return NULL;
} }
@ -11040,10 +11044,10 @@ STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
static int static int
nogvl_wait_for_single_fd(VALUE th, int fd, short events) 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) { if (scheduler != Qnil) {
struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events}; 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); return RTEST(args.result);
} }
@ -11059,10 +11063,10 @@ nogvl_wait_for_single_fd(VALUE th, int fd, short events)
static int static int
nogvl_wait_for_single_fd(VALUE th, int fd, short events) 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) { if (scheduler != Qnil) {
struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events}; 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); return RTEST(args.result);
} }

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

@ -13,7 +13,7 @@
#include "ruby/internal/config.h" #include "ruby/internal/config.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#include "coroutine/Stack.h" #include "coroutine/Stack.h"
#include <ctype.h> #include <ctype.h>
@ -1345,10 +1345,9 @@ rb_process_status_wait(rb_pid_t pid, int flags)
{ {
// We only enter the scheduler if we are "blocking": // We only enter the scheduler if we are "blocking":
if (!(flags & WNOHANG)) { if (!(flags & WNOHANG)) {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (rb_scheduler_supports_process_wait(scheduler)) { VALUE result = rb_fiber_scheduler_process_wait(scheduler, pid, flags);
return rb_scheduler_process_wait(scheduler, pid, flags); if (result != Qundef) return result;
}
} }
COROUTINE_STACK_LOCAL(struct waitpid_state, w); COROUTINE_STACK_LOCAL(struct waitpid_state, w);
@ -5104,10 +5103,10 @@ static VALUE
rb_f_sleep(int argc, VALUE *argv, VALUE _) rb_f_sleep(int argc, VALUE *argv, VALUE _)
{ {
time_t beg = time(0); time_t beg = time(0);
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
rb_scheduler_kernel_sleepv(scheduler, argc, argv); rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
} }
else { else {
if (argc == 0) { if (argc == 0) {

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

@ -9,7 +9,7 @@
**********************************************************************/ **********************************************************************/
#include "vm_core.h" #include "vm_core.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#include "ruby/io.h" #include "ruby/io.h"
static ID id_close; static ID id_close;
@ -25,7 +25,7 @@ static ID id_io_write;
static ID id_io_wait; static ID id_io_wait;
void void
Init_Scheduler(void) Init_Fiber_Scheduler(void)
{ {
id_close = rb_intern_const("close"); id_close = rb_intern_const("close");
@ -41,7 +41,7 @@ Init_Scheduler(void)
} }
VALUE VALUE
rb_scheduler_get(void) rb_fiber_scheduler_get(void)
{ {
rb_thread_t *thread = GET_THREAD(); rb_thread_t *thread = GET_THREAD();
VM_ASSERT(thread); VM_ASSERT(thread);
@ -50,14 +50,14 @@ rb_scheduler_get(void)
} }
VALUE VALUE
rb_scheduler_set(VALUE scheduler) rb_fiber_scheduler_set(VALUE scheduler)
{ {
rb_thread_t *thread = GET_THREAD(); rb_thread_t *thread = GET_THREAD();
VM_ASSERT(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. // 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) { if (thread->scheduler != Qnil) {
rb_scheduler_close(thread->scheduler); rb_fiber_scheduler_close(thread->scheduler);
} }
thread->scheduler = scheduler; thread->scheduler = scheduler;
@ -66,7 +66,7 @@ rb_scheduler_set(VALUE scheduler)
} }
static VALUE static VALUE
rb_threadptr_scheduler_current(rb_thread_t *thread) rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
{ {
VM_ASSERT(thread); VM_ASSERT(thread);
@ -78,18 +78,18 @@ rb_threadptr_scheduler_current(rb_thread_t *thread)
} }
VALUE 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 VALUE
rb_scheduler_close(VALUE scheduler) rb_fiber_scheduler_close(VALUE scheduler)
{ {
if (rb_respond_to(scheduler, id_close)) { if (rb_respond_to(scheduler, id_close)) {
return rb_funcall(scheduler, id_close, 0); return rb_funcall(scheduler, id_close, 0);
@ -99,7 +99,7 @@ rb_scheduler_close(VALUE scheduler)
} }
VALUE VALUE
rb_scheduler_timeout(struct timeval *timeout) rb_fiber_scheduler_make_timeout(struct timeval *timeout)
{ {
if (timeout) { if (timeout) {
return rb_float_new((double)timeout->tv_sec + (0.000001f * timeout->tv_usec)); return rb_float_new((double)timeout->tv_sec + (0.000001f * timeout->tv_usec));
@ -109,80 +109,74 @@ rb_scheduler_timeout(struct timeval *timeout)
} }
VALUE 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); return rb_funcall(scheduler, id_kernel_sleep, 1, timeout);
} }
VALUE 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); return rb_funcallv(scheduler, id_kernel_sleep, argc, argv);
} }
int VALUE
rb_scheduler_supports_process_wait(VALUE scheduler) 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 VALUE
rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags) rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
{
return rb_funcall(scheduler, id_process_wait, 2, PIDT2NUM(pid), RB_INT2NUM(flags));
}
VALUE
rb_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
{ {
return rb_funcall(scheduler, id_block, 2, blocker, timeout); return rb_funcall(scheduler, id_block, 2, blocker, timeout);
} }
VALUE 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); return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
} }
VALUE 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); return rb_funcall(scheduler, id_io_wait, 3, io, events, timeout);
} }
VALUE 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 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); return rb_fiber_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);
} }
VALUE 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)); VALUE arguments[] = {
} io, buffer, SIZET2NUM(offset), SIZET2NUM(length)
};
int
rb_scheduler_supports_io_write(VALUE scheduler) return rb_check_funcall(scheduler, id_io_read, 4, arguments);
{
return rb_respond_to(scheduler, id_io_write);
} }
VALUE 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. // 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);
} }

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

@ -15,24 +15,25 @@ def fetch_topics(topics)
topics.each do |topic| topics.each do |topic|
Fiber.new(blocking: Fiber.current.blocking?) do Fiber.new(blocking: Fiber.current.blocking?) do
uri = URI("https://www.google.com/search?q=#{topic}") 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.resume
end end
Thread.fiber_scheduler&.run Fiber.scheduler&.run
return responses return responses
end end
def sweep(repeats: 3, **options) def sweep(repeats: 3, **options)
times = (1..8).map do |i| times = (1..8).map do |i|
$stderr.puts "Measuring #{i} topic(s)..." $stderr.puts "Measuring #{i} topic(s) #{options.inspect}..."
topics = TOPICS[0...i] topics = TOPICS[0...i]
Thread.new do Thread.new do
Benchmark.realtime do Benchmark.realtime do
scheduler = Scheduler.new scheduler = Scheduler.new
Fiber.set_scheduler scheduler Fiber.set_scheduler(scheduler)
repeats.times do repeats.times do
Fiber.new(**options) do Fiber.new(**options) do
@ -49,5 +50,5 @@ def sweep(repeats: 3, **options)
puts JSON.dump(times.map{|value| value.round(3)}) puts JSON.dump(times.map{|value| value.round(3)})
end end
sweep(blocking: true) # sweep(blocking: true)
sweep(blocking: false) sweep(blocking: false)

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

@ -47,6 +47,8 @@ class Scheduler
end end
def run def run
# $stderr.puts [__method__, Fiber.current].inspect
while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive? while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive?
# Can only handle file descriptors up to 1024... # Can only handle file descriptors up to 1024...
readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout) 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 "readable: #{readable}" if readable&.any?
# puts "writable: #{writable}" if writable&.any? # puts "writable: #{writable}" if writable&.any?
selected = {}
readable&.each do |io| readable&.each do |io|
if fiber = @readable.delete(io) if fiber = @readable.delete(io)
fiber.resume selected[fiber] = IO::READABLE
elsif io == @urgent.first elsif io == @urgent.first
@urgent.first.read_nonblock(1024) @urgent.first.read_nonblock(1024)
end end
@ -64,10 +68,14 @@ class Scheduler
writable&.each do |io| writable&.each do |io|
if fiber = @writable.delete(io) if fiber = @writable.delete(io)
fiber.resume selected[fiber] |= IO::WRITABLE
end end
end end
selected.each do |fiber, events|
fiber.resume(events)
end
if @waiting.any? if @waiting.any?
time = current_time time = current_time
waiting, @waiting = @waiting, {} waiting, @waiting = @waiting, {}
@ -96,6 +104,8 @@ class Scheduler
end end
def close def close
# $stderr.puts [__method__, Fiber.current].inspect
raise "Scheduler already closed!" if @closed raise "Scheduler already closed!" if @closed
self.run self.run
@ -118,6 +128,8 @@ class Scheduler
end end
def process_wait(pid, flags) 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: # This is a very simple way to implement a non-blocking wait:
Thread.new do Thread.new do
Process::Status.wait(pid, flags) Process::Status.wait(pid, flags)
@ -125,6 +137,8 @@ class Scheduler
end end
def io_wait(io, events, duration) def io_wait(io, events, duration)
# $stderr.puts [__method__, io, events, duration, Fiber.current].inspect
unless (events & IO::READABLE).zero? unless (events & IO::READABLE).zero?
@readable[io] = Fiber.current @readable[io] = Fiber.current
end end
@ -134,12 +148,12 @@ class Scheduler
end end
Fiber.yield Fiber.yield
return true
end end
# Used for Kernel#sleep and Mutex#sleep # Used for Kernel#sleep and Mutex#sleep
def kernel_sleep(duration = nil) def kernel_sleep(duration = nil)
# $stderr.puts [__method__, duration, Fiber.current].inspect
self.block(:sleep, duration) self.block(:sleep, duration)
return true return true
@ -171,6 +185,8 @@ class Scheduler
# This might be called from another thread. # This might be called from another thread.
def unblock(blocker, fiber) def unblock(blocker, fiber)
# $stderr.puts [__method__, blocker, fiber].inspect # $stderr.puts [__method__, blocker, fiber].inspect
# $stderr.puts blocker.backtrace.inspect
# $stderr.puts fiber.backtrace.inspect
@lock.synchronize do @lock.synchronize do
@ready << fiber @ready << fiber

45
test/fiber/test_thread.rb Normal file
Просмотреть файл

@ -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

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

@ -81,7 +81,7 @@
#include "internal/io.h" #include "internal/io.h"
#include "internal/object.h" #include "internal/object.h"
#include "internal/proc.h" #include "internal/proc.h"
#include "internal/scheduler.h" #include "ruby/fiber/scheduler.h"
#include "internal/signal.h" #include "internal/signal.h"
#include "internal/thread.h" #include "internal/thread.h"
#include "internal/time.h" #include "internal/time.h"
@ -551,8 +551,8 @@ rb_threadptr_join_list_wakeup(rb_thread_t *thread)
while (join_list) { while (join_list) {
rb_thread_t *target_thread = join_list->thread; rb_thread_t *target_thread = join_list->thread;
if (target_thread->scheduler != Qnil) { if (target_thread->scheduler != Qnil && rb_fiberptr_blocking(join_list->fiber) == 0) {
rb_scheduler_unblock(target_thread->scheduler, target_thread->self, rb_fiberptr_self(join_list->fiber)); rb_fiber_scheduler_unblock(target_thread->scheduler, target_thread->self, rb_fiberptr_self(join_list->fiber));
} else { } else {
rb_threadptr_interrupt(target_thread); rb_threadptr_interrupt(target_thread);
@ -772,7 +772,7 @@ thread_do_start(rb_thread_t *th)
rb_bug("unreachable"); 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); 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) { while (target_th->status != THREAD_KILLED) {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { 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) { } else if (!limit) {
th->status = THREAD_STOPPED_FOREVER; th->status = THREAD_STOPPED_FOREVER;
rb_ractor_sleeper_threads_inc(th->ractor); rb_ractor_sleeper_threads_inc(th->ractor);
@ -1525,9 +1525,9 @@ rb_thread_sleep_interruptible(void)
static void static void
rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker) rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker)
{ {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
rb_scheduler_block(scheduler, blocker, Qnil); rb_fiber_scheduler_block(scheduler, blocker, Qnil);
} else { } else {
thread_debug("rb_thread_sleep_deadly_allow_spurious_wakeup\n"); thread_debug("rb_thread_sleep_deadly_allow_spurious_wakeup\n");
sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE); sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE);

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

@ -32,8 +32,8 @@ sync_wakeup(struct list_head *head, long max)
if (cur->th->status != THREAD_KILLED) { if (cur->th->status != THREAD_KILLED) {
if (cur->th->scheduler != Qnil) { if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) {
rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); rb_fiber_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber));
} else { } else {
rb_threadptr_interrupt(cur->th); rb_threadptr_interrupt(cur->th);
cur->th->status = THREAD_RUNNABLE; 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) { static VALUE call_rb_fiber_scheduler_block(VALUE mutex) {
return rb_scheduler_block(rb_scheduler_current(), mutex, Qnil); return rb_fiber_scheduler_block(rb_fiber_scheduler_current(), mutex, Qnil);
} }
static VALUE static VALUE
@ -302,7 +302,7 @@ do_mutex_lock(VALUE self, int interruptible_p)
} }
while (mutex->fiber != fiber) { while (mutex->fiber != fiber) {
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
COROUTINE_STACK_LOCAL(struct sync_waiter, w); COROUTINE_STACK_LOCAL(struct sync_waiter, w);
w->self = self; w->self = self;
@ -311,7 +311,7 @@ do_mutex_lock(VALUE self, int interruptible_p)
list_add_tail(&mutex->waitq, &w->node); 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) { if (!mutex->fiber) {
mutex->fiber = 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_for_each_safe(&mutex->waitq, cur, next, node) {
list_del_init(&cur->node); list_del_init(&cur->node);
if (cur->th->scheduler != Qnil) { if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) {
rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); rb_fiber_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber));
goto found; goto found;
} else { } else {
switch (cur->th->status) { switch (cur->th->status) {
@ -545,9 +545,9 @@ rb_mutex_sleep(VALUE self, VALUE timeout)
rb_mutex_unlock(self); rb_mutex_unlock(self);
time_t beg = time(0); time_t beg = time(0);
VALUE scheduler = rb_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
rb_scheduler_kernel_sleep(scheduler, timeout); rb_fiber_scheduler_kernel_sleep(scheduler, timeout);
mutex_lock_uninterruptible(self); mutex_lock_uninterruptible(self);
} else { } else {
if (NIL_P(timeout)) { if (NIL_P(timeout)) {