Project

General

Profile

Bug #18482

Updated by jakit (Jakit Liang) almost 3 years ago

class Fiber can not disable scheduler with it's parameter. 

 When parameter is false: `false`: 

 ``` 
 require 'fiber' 
 require 'io/nonblock' 

 class SimpleScheduler 
   def initialize 
     @readable = {} 
     @writable = {} 
     @waiting = {} 
     @ready = [] 
     @blocking = 0 
     @urgent = IO.pipe 
   end 

   def run 
     while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive? or @ready.any? 
       readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], 0) 

       readable&.each do |io| 
         if fiber = @readable.delete(io) 
           fiber.resume 
         end 
       end 

       writable&.each do |io| 
         if fiber = @writable.delete(io) 
           fiber.resume 
         end 
       end 

       @waiting.keys.each do |fiber| 
         if current_time > @waiting[fiber] 
           @waiting.delete(fiber) 
           fiber.resume 
         end 
       end 

       ready, @ready = @ready, [] 
       ready.each do |fiber| 
         fiber.resume 
       end 
     end 
   end 

   def io_wait(io, events, timeout) 
     unless (events & IO::READABLE).zero? 
       @readable[io] = Fiber.current 
     end 
     unless (events & IO::WRITABLE).zero? 
       @writable[io] = Fiber.current 
     end 

     Fiber.yield 
     return events 
   end 

   def kernel_sleep(duration = nil) 
     block(:sleep, duration) 
     return true 
   end 

   def block(blocker, timeout = nil) 
     if timeout 
       @waiting[Fiber.current] = current_time + timeout 
       begin 
         Fiber.yield 
       ensure 
         @waiting.delete(Fiber.current) 
       end 
     else 
       @blocking += 1 
       begin 
         Fiber.yield 
       ensure 
         @blocking -= 1 
       end 
     end 
   end 

   def unblock(blocker, fiber) 
     @ready << fiber 
     io = @urgent.last 
     io.write_nonblock('.') 
   end 

   def close 
     run 
     @urgent.each(&:close) 
     @urgent = nil 
   end 

   private 
   def current_time 
     Process.clock_gettime(Process::CLOCK_MONOTONIC) 
   end 
 end 

 scheduler = SimpleScheduler.new 
 Fiber.set_scheduler(scheduler) 

 puts "Go to sleep!" 

 f = Fiber.new(false) do 
   puts "Going to sleep" 
   sleep(1) 
   puts "I slept well" 
 end 

 f.resume 

 puts "Wakey-wakey, sleepyhead" 
 ``` 

 Result: 

 ``` 
 Go to sleep! 
 Going to sleep 
 Wakey-wakey, sleepyhead 
 I slept well 
 ``` 

 And when When parameter is true: `true`: 

 ``` 
 require 'fiber' 
 require 'io/nonblock' 

 class SimpleScheduler 
   def initialize 
     @readable = {} 
     @writable = {} 
     @waiting = {} 
     @ready = [] 
     @blocking = 0 
     @urgent = IO.pipe 
   end 

   def run 
     while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive? or @ready.any? 
       readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], 0) 

       readable&.each do |io| 
         if fiber = @readable.delete(io) 
           fiber.resume 
         end 
       end 

       writable&.each do |io| 
         if fiber = @writable.delete(io) 
           fiber.resume 
         end 
       end 

       @waiting.keys.each do |fiber| 
         if current_time > @waiting[fiber] 
           @waiting.delete(fiber) 
           fiber.resume 
         end 
       end 

       ready, @ready = @ready, [] 
       ready.each do |fiber| 
         fiber.resume 
       end 
     end 
   end 

   def io_wait(io, events, timeout) 
     unless (events & IO::READABLE).zero? 
       @readable[io] = Fiber.current 
     end 
     unless (events & IO::WRITABLE).zero? 
       @writable[io] = Fiber.current 
     end 

     Fiber.yield 
     return events 
   end 

   def kernel_sleep(duration = nil) 
     block(:sleep, duration) 
     return true 
   end 

   def block(blocker, timeout = nil) 
     if timeout 
       @waiting[Fiber.current] = current_time + timeout 
       begin 
         Fiber.yield 
       ensure 
         @waiting.delete(Fiber.current) 
       end 
     else 
       @blocking += 1 
       begin 
         Fiber.yield 
       ensure 
         @blocking -= 1 
       end 
     end 
   end 

   def unblock(blocker, fiber) 
     @ready << fiber 
     io = @urgent.last 
     io.write_nonblock('.') 
   end 

   def close 
     run 
     @urgent.each(&:close) 
     @urgent = nil 
   end 

   private 
   def current_time 
     Process.clock_gettime(Process::CLOCK_MONOTONIC) 
   end 
 end 

 scheduler = SimpleScheduler.new 
 Fiber.set_scheduler(scheduler) 

 puts "Go to sleep!" 

 f = Fiber.new(true) Fiber.new(false) do 
   puts "Going to sleep" 
   sleep(1) 
   puts "I slept well" 
 end 

 f.resume 

 puts "Wakey-wakey, sleepyhead" 
 ``` 

 Result (was still the same): 

 ``` 
 Go to sleep! 
 Going to sleep 
 Wakey-wakey, sleepyhead 
 I slept well 
 ``` 

Back