SASADA Koichi <ko1 / ruby-lang.org> wrote:
> Hi Eric,
> 
> I agree it is possible to use M:N model.
> 
> There are several problem mainly because of C extensions (and libraries
> which C extensions use).
> 
> 1.We can't move execution context across native threads by userland
>   because some libraries can use thread local variables used by
>   native thread system.
>   Also because some libraries can depends on C-stack layout.

Hi ko1, thank you for response.

Correct, I'm not sure if this can be changed while maintaining
compatibility.  Anyways I think I am fine with this limitation
where a Fiber is always tied to a particular native thread.

> 2.Some libraries can stop threads because of uncontrollable
>   I/O operations (wait for IO (network) with system calls),
>   uncontrollable system synchronization (mutex, semaphore, ...),
>   big computation (like mathematical computation).
> 
> Current 1:1 thread model does not have such issues (if C extensions
> release GVL correctly), so we employee it.
> However, the overhead of thread creation and thread switching is high,
> as you say.
> 
> However, the issues 1 and 2 are *possible* issues. We don't know which
> libraries have a problem. If we only use managed C extensions, there are
> no problem to use M:N mode.

2 is tricky.  I think in worst case (no modifying existing C
exts or API), M:N will degrade to current 1:1 model, which
retains 100% compatibility with current Ruby 1.9/2.x code.

> For Ruby 3, Matz want to encourage such fine grain context switching. We
> discussed before and we planed to introduce automatic Fiber switching at
> specific I/O operation. It is small version of your proposal, it is one
> possibility (and it is easy than complete M:N model). I'll change Fiber
> context management to lightwieght switching for Ruby 2.5 and try it at
> later versions.

Cool!  I was thinking along the same lines.  I think Ruby Thread
class can become a subclass of Fiber with automatic switching.

However, to spawn native threads:

If a Thread uses existing GVL release C-API, then the _next_
Thread.new call will create a native thread (and future
Thread.new will be subclass of Fiber in new native thread).

So, in pseudo code:

  class Thread < Fiber
    def self.new
      case Thread.current[:gvl_state]
      when :none
         # default
         super # M += 1
      when :released
        # this is set by BLOCKING_REGION GVL release
        # only allow a user-level thread to spawn one new native thread
	Thread.current[:gvl_state] = :spawned

        NativeThread.new { Thread.new } # N += 1
      when :spawned
        # We already spawned on native thread from this user-level
	# thread, only spawn new user-level thread for now.
	super # M += 1
      end
    end
  end

Current GVL release operations will change
Thread.current[:gvl_state] from :none -> :released

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>