class Async::Reactor

def run_once(timeout = nil)

Returns:
  • (Boolean) - whether there is more work to do.

Parameters:
  • timeout (Float | nil) -- the maximum timeout, or if nil, indefinite.
def run_once(timeout = nil)
	# Console.logger.debug(self) {"@ready = #{@ready} @running = #{@running}"}
	
	if @ready.any?
		# running used to correctly answer on `finished?`, and to reuse Array object.
		@running, @ready = @ready, @running
		
		@running.each do |fiber|
			fiber.resume if fiber.alive?
		end
		
		@running.clear
	end
	
	if @unblocked.any?
		unblocked = Array.new
		
		@guard.synchronize do
			unblocked, @unblocked = @unblocked, unblocked
		end
		
		while fiber = unblocked.pop
			fiber.resume if fiber.alive?
		end
	end
	
	if @ready.empty?
		interval = @timers.wait_interval
	else
		# if there are tasks ready to execute, don't sleep:
		interval = 0
	end
	
	# If we are finished, we stop the task tree and exit:
	if self.finished?
		return false
	end
	
	# If there is no interval to wait (thus no timers), and no tasks, we could be done:
	if interval.nil?
		# Allow the user to specify a maximum interval if we would otherwise be sleeping indefinitely:
		interval = timeout
	elsif interval < 0
		# We have timers ready to fire, don't sleep in the selctor:
		interval = 0
	elsif timeout and interval > timeout
		interval = timeout
	end
	
	# Console.logger.info(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
	if monitors = @selector.select(interval)
		monitors.each do |monitor|
			monitor.value.resume
		end
	end
	
	@timers.fire
	
	# We check and clear the interrupted flag here:
	if @interrupted
		@guard.synchronize do
			@interrupted = false
		end
		
		return false
	end
	
	# The reactor still has work to do:
	return true
end