class Opal::BuilderScheduler::Prefork
def fork_count
def fork_count ENV['OPAL_PREFORK_THREADS']&.to_i || (Etc.nprocessors * 3 / 4.0).ceil end
def fork_entrypoint(io)
def fork_entrypoint(io) # Ensure we can work with our forks async... Fiber.set_scheduler(nil) if Fiber.respond_to? :set_scheduler @in_fork = io until io.eof? $0 = 'opal/builder: idle' type, *args = *io.recv case type when :compile rel_path, req, autoloads, options = *args $0 = "opal/builder: #{req}" begin asset = builder.process_require_threadsafely(req, autoloads, options) io.send(:new_asset, asset) rescue Builder::MissingRequire => error io.send(:missing_require_exception, rel_path, error) end when :close io.goodbye break end end rescue Errno::EPIPE exit! end
def prefork
def prefork @forks = ForkSet.new(fork_count, &method(:fork_entrypoint)) end
def prefork_reactor(rel_path, requires, autoloads, options)
def prefork_reactor(rel_path, requires, autoloads, options) prefork processed = [] first = rel_path queue = requires.map { |i| [rel_path, i, autoloads, options] } awaiting = 0 built = 0 should_log = $stderr.tty? && !ENV['OPAL_DISABLE_PREFORK_LOGS'] $stderr.print "\r\e[K" if should_log loop do events, idles = @forks.get_events(queue.length) idles.each do |io| break if queue.empty? rel_path, req, autoloads, options = *queue.shift next if builder.already_processed.include?(req) awaiting += 1 builder.already_processed << req io.send(:compile, rel_path, req, autoloads, options) end events.each do |io, type, *args| case type when :new_requires rel_path, requires, autoloads, options = *args requires.each do |i| queue << [rel_path, i, autoloads, options] end when :new_asset asset, = *args if !asset # Do nothing, we received a nil which is expected. else processed << asset end built += 1 awaiting -= 1 when :missing_require_exception rel_path, error = *args raise error, "A file required by #{rel_path.inspect} wasn't found.\n#{error.message}", error.backtrace when :exception error, = *args raise error when :close io.goodbye end end if should_log percent = (100.0 * built / (awaiting + built)).round(1) str = format("[opal/builder] Building %<first>s... (%<percent>4.3g%%)\r", first: first, percent: percent) $stderr.print str end break if awaiting == 0 && queue.empty? end processed ensure $stderr.print "\r\e[K\r" if should_log @forks.close @forks.wait end
def process_requires(rel_path, requires, autoloads, options)
def process_requires(rel_path, requires, autoloads, options) return if requires.empty? if @in_fork io = @in_fork io.send(:new_requires, rel_path, requires, autoloads, options) else processed = prefork_reactor(rel_path, requires, autoloads, options) processed = OrderCorrector.correct_order(processed, requires, builder) builder.processed.append(*processed) end end