ruby-changes:66656
From: Samuel <ko1@a...>
Date: Thu, 1 Jul 2021 08:23:49 +0900 (JST)
Subject: [ruby-changes:66656] 42130a64f0 (master): Replace copy coroutine with pthread implementation.
https://git.ruby-lang.org/ruby.git/commit/?id=42130a64f0 From 42130a64f02294dc8025af3a51bda518c67ab33d Mon Sep 17 00:00:00 2001 From: Samuel Williams <samuel.williams@o...> Date: Sat, 26 Jun 2021 10:17:26 +1200 Subject: Replace copy coroutine with pthread implementation. --- .github/workflows/compilers.yml | 2 +- NEWS.md | 3 + bootstraptest/test_fiber.rb | 4 +- configure.ac | 8 +- cont.c | 141 ++++++++++----------- coroutine/Stack.h | 21 ---- coroutine/amd64/Context.h | 1 + coroutine/arm32/Context.h | 1 + coroutine/arm64/Context.h | 1 + coroutine/copy/Context.c | 162 ------------------------ coroutine/copy/Context.h | 98 --------------- coroutine/emscripten/Context.h | 1 + coroutine/ppc64le/Context.h | 1 + coroutine/pthread/Context.c | 268 ++++++++++++++++++++++++++++++++++++++++ coroutine/pthread/Context.h | 63 ++++++++++ coroutine/riscv64/Context.h | 1 + coroutine/ucontext/Context.c | 1 + coroutine/ucontext/Context.h | 1 + coroutine/win32/Context.h | 1 + coroutine/win64/Context.h | 1 + coroutine/x86/Context.h | 1 + eval.c | 5 - eval_intern.h | 4 +- process.c | 24 ++-- test/ruby/test_fiber.rb | 5 +- thread.c | 22 ++-- thread_pthread.c | 4 +- thread_sync.c | 85 ++++++------- thread_win32.c | 4 +- vm_core.h | 7 +- 30 files changed, 492 insertions(+), 449 deletions(-) delete mode 100644 coroutine/Stack.h delete mode 100644 coroutine/copy/Context.c delete mode 100644 coroutine/copy/Context.h create mode 100644 coroutine/pthread/Context.c create mode 100644 coroutine/pthread/Context.h diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 3bd7bab..ea19c01 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -93,7 +93,7 @@ jobs: https://github.com/ruby/ruby/blob/trunk/.github/workflows/compilers.yml#L93 - { key: append_configure, name: jemalloc, value: '--with-jemalloc' } - { key: append_configure, name: valgrind, value: '--with-valgrind' } - { key: append_configure, name: 'coroutine=ucontext', value: '--with-coroutine=ucontext' } - - { key: append_configure, name: 'coroutine=copy', value: '--with-coroutine=copy' } + - { key: append_configure, name: 'coroutine=pthread', value: '--with-coroutine=pthread' } - { key: append_configure, name: disable-jit-support, value: '--disable-jit-support' } - { key: append_configure, name: disable-dln, value: '--disable-dln' } - { key: append_configure, name: disable-rubygems, value: '--disable-rubygems' } diff --git a/NEWS.md b/NEWS.md index 68ae707..00102ff 100644 --- a/NEWS.md +++ b/NEWS.md @@ -128,6 +128,8 @@ Outstanding ones only. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L128 * Make `Monitor` fiber-safe. [[Bug #17827]] + * Replace copy coroutine with pthread implementation. [[Feature #18015]] + ## Stdlib updates Outstanding ones only. @@ -193,3 +195,4 @@ Excluding feature bug fixes. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L195 [Feature #17470]: https://bugs.ruby-lang.org/issues/17470 [Feature #17853]: https://bugs.ruby-lang.org/issues/17853 [Bug #17827]: https://bugs.ruby-lang.org/issues/17827 +[Feature #18015]: https://bugs.ruby-lang.org/issues/18015 diff --git a/bootstraptest/test_fiber.rb b/bootstraptest/test_fiber.rb index 35e1bf6..2614dd1 100644 --- a/bootstraptest/test_fiber.rb +++ b/bootstraptest/test_fiber.rb @@ -19,12 +19,12 @@ assert_equal %q{ok}, %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_fiber.rb#L19 } assert_equal %q{ok}, %q{ - 10_000.times.collect{Fiber.new{}} + 100.times.collect{Fiber.new{}} :ok } assert_equal %q{ok}, %q{ - fibers = 100.times.collect{Fiber.new{Fiber.yield}} + fibers = 1000.times.collect{Fiber.new{Fiber.yield}} fibers.each(&:resume) fibers.each(&:resume) :ok diff --git a/configure.ac b/configure.ac index 90b5a75..f74dbdc 100644 --- a/configure.ac +++ b/configure.ac @@ -2533,10 +2533,10 @@ AS_CASE([$coroutine_type], [yes|''], [ https://github.com/ruby/ruby/blob/trunk/configure.ac#L2533 coroutine_type=x86 ], [*-openbsd*], [ - coroutine_type=copy + coroutine_type=pthread ], [*-haiku*], [ - coroutine_type=copy + coroutine_type=pthread ], [*-emscripten*], [ coroutine_type=emscripten @@ -2544,7 +2544,7 @@ AS_CASE([$coroutine_type], [yes|''], [ https://github.com/ruby/ruby/blob/trunk/configure.ac#L2544 [ AC_CHECK_FUNCS([getcontext swapcontext makecontext], [coroutine_type=ucontext], - [coroutine_type=copy; break] + [coroutine_type=pthread; break] ) ] ) @@ -2554,7 +2554,7 @@ COROUTINE_H=coroutine/$coroutine_type/Context.h https://github.com/ruby/ruby/blob/trunk/configure.ac#L2554 AS_IF([test ! -f "$srcdir/$COROUTINE_H"], [AC_MSG_ERROR('$coroutine_type' is not supported as coroutine)]) AS_CASE([$coroutine_type], - [copy|ucontext], [ + [ucontext|pthread], [ COROUTINE_SRC=coroutine/$coroutine_type/Context.c ], [ diff --git a/cont.c b/cont.c index 00ab1e9..d72d29e 100644 --- a/cont.c +++ b/cont.c @@ -711,10 +711,51 @@ fiber_pool_stack_release(struct fiber_pool_stack * stack) https://github.com/ruby/ruby/blob/trunk/cont.c#L711 #endif } +void rb_fiber_start(rb_fiber_t*); + +static inline void +ec_switch(rb_thread_t *th, rb_fiber_t *fiber) +{ + rb_execution_context_t *ec = &fiber->cont.saved_ec; + rb_ractor_set_current_ec(th->ractor, th->ec = ec); + // ruby_current_execution_context_ptr = th->ec = ec; + + /* + * timer-thread may set trap interrupt on previous th->ec at any time; + * ensure we do not delay (or lose) the trap interrupt handling. + */ + if (th->vm->ractor.main_thread == th && + rb_signal_buff_size() > 0) { + RUBY_VM_SET_TRAP_INTERRUPT(ec); + } + + VM_ASSERT(ec->fiber_ptr->cont.self == 0 || ec->vm_stack != NULL); +} + +static inline void +fiber_restore_thread(rb_thread_t *th, rb_fiber_t *fiber) +{ + ec_switch(th, fiber); + VM_ASSERT(th->ec->fiber_ptr == fiber); +} + static COROUTINE fiber_entry(struct coroutine_context * from, struct coroutine_context * to) { - rb_fiber_start(); + rb_fiber_t *fiber = to->argument; + rb_thread_t *thread = fiber->cont.saved_ec.thread_ptr; + +#ifdef COROUTINE_PTHREAD_CONTEXT + ruby_thread_set_native(thread); +#endif + + fiber_restore_thread(thread, fiber); + + rb_fiber_start(fiber); + +#ifndef COROUTINE_PTHREAD_CONTEXT + VM_UNREACHABLE(fiber_entry); +#endif } // Initialize a fiber's coroutine's machine stack and vm stack. @@ -731,22 +772,13 @@ fiber_initialize_coroutine(rb_fiber_t *fiber, size_t * vm_stack_size) https://github.com/ruby/ruby/blob/trunk/cont.c#L772 vm_stack = fiber_pool_stack_alloca(&fiber->stack, fiber_pool->vm_stack_size); *vm_stack_size = fiber_pool->vm_stack_size; -#ifdef COROUTINE_PRIVATE_STACK - coroutine_initialize(&fiber->context, fiber_entry, fiber_pool_stack_base(&fiber->stack), fiber->stack.available, sec->machine.stack_start); - // The stack for this execution context is still the main machine stack, so don't adjust it. - // If this is not managed correctly, you will fail in `rb_ec_stack_check`. - - // We limit the machine stack usage to the fiber stack size. - if (sec->machine.stack_maxsize > fiber->stack.available) { - sec->machine.stack_maxsize = fiber->stack.available; - } -#else coroutine_initialize(&fiber->context, fiber_entry, fiber_pool_stack_base(&fiber->stack), fiber->stack.available); // The stack for this execution context is the one we allocated: sec->machine.stack_start = fiber->stack.current; sec->machine.stack_maxsize = fiber->stack.available; -#endif + + fiber->context.argument = (void*)fiber; return vm_stack; } @@ -815,25 +847,6 @@ fiber_status_set(rb_fiber_t *fiber, enum fiber_status s) https://github.com/ruby/ruby/blob/trunk/cont.c#L847 fiber->status = s; } -static inline void -ec_switch(rb_thread_t *th, rb_fiber_t *fiber) -{ - rb_execution_context_t *ec = &fiber->cont.saved_ec; - rb_ractor_set_current_ec(th->ractor, th->ec = ec); - // ruby_current_execution_context_ptr = th->ec = ec; - - /* - * timer-thread may set trap interrupt on previous th->ec at any time; - * ensure we do not delay (or lose) the trap interrupt handling. - */ - if (th->vm->ractor.main_thread == th && - rb_signal_buff_size() > 0) { - RUBY_VM_SET_TRAP_INTERRUPT(ec); - } - - VM_ASSERT(ec->fiber_ptr->cont.self == 0 || ec->vm_stack != NULL); -} - static rb_context_t * cont_ptr(VALUE obj) { @@ -1041,7 +1054,7 @@ fiber_free(void *ptr) https://github.com/ruby/ruby/blob/trunk/cont.c#L1054 rb_fiber_t *fiber = ptr; RUBY_FREE_ENTER("fiber"); - //if (DEBUG) fprintf(stderr, "fiber_free: %p[%p]\n", fiber, fiber->stack.base); + if (DEBUG) fprintf(stderr, "fiber_free: %p[%p]\n", fiber, fiber->stack.base); if (fiber->cont.saved_ec.local_storage) { rb_id_table_free(fiber->cont.saved_ec.local_storage); @@ -1278,13 +1291,6 @@ cont_capture(volatile int *volatile stat) https://github.com/ruby/ruby/blob/trunk/cont.c#L1291 COMPILER_WARNING_POP static inline void -fiber_restore_thread(rb_thread_t *th, rb_fiber_t *fiber) -{ - ec_switch(th, fiber); - VM_ASSERT(th->ec->fiber_ptr == fiber); -} - -static inline void cont_restore_thread(rb_context_t *cont) { rb_thread_t *th = GET_THREAD(); @@ (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/