Project

General

Profile

Feature #20627

Updated by ko1 (Koichi Sasada) 5 months ago

Now `require` on main Ractor is not allowed (raising error) but it is hard, especially for `autoload`. 
 So let's allow `require` by running it on the main Ractor. 

 ## Background 

 On many libraries it is needed to run loading on the main Ractors because: 

 1. Setup constants with unshareable objects (such as `C = []`) are not allowed on non main Ractors. 
 2. Setup global variables and class variables are not allowed. `$LOADED_FEATURES` is also untouchable. 
 3. (maybe more reasons) 

 So the `require` on non main Ractors is not allowed. 

 However it is hard to program especially on `autoload`. 
 Also dynamic `require` (`require` in methods) are not allowed too (`pp` method, for example). 

 ## Proposal 

 Allow `require` on non main Ractors by running `require` process on the main Ractor. 

 ![](clipboard-202407111201-kaiem.png) 

 (quoted on my talk at RubyKaigi 2024) 

 ### `rb_ractor_interrupt_exec(target_ractor, func)` C-API 

 Make a thread on `target_ractor` and run `func` (C function) on it. 

 I think it is safe to expose on Ruby API because running `func` on a *newly created* thread (do not disturb running target threads). But now it is proposed as only (hidden) C-API. 

 ### New Ractor methods 

 - `Ractor.main?` returns Ractors 
 - `Ractor.require(feature)` do `require` on the main Ractor 

 These new methods are useful for users who override `require` method like [RubyGems](https://github.com/ruby/ruby/blob/master/lib/rubygems/core_ext/kernel_require.rb#L36). 

 ```ruby 
 alias orig_require require 

 def require feature 
   return Rator.require(feature) unless Ractor.main? 

   # overriding require code 
 end 
 ``` 

 Or we can prepend a module like: 

 ```ruby 
 Module.new do 
   def require(feature) 
     return Rator.require(feature) if defined?(Ractor.main?) && !Ractor.main? unless Ractor.main?     
     super(feature) 
   end 
   Kernel.prepend self 
 end   
 ``` 

 will support ractors for all overgrinding methods. But not sure it is acceptable to add additional one modules in ancestors by `prepend`. 

 Also this technique doesn't support require overriding by prepending. 

 ## Implementation 

 https://github.com/ruby/ruby/pull/11142 (not matured yet) 

Back