Require what to be notified for with block and Subprocess.execute

There was an issue before where the stdin buffer would always have space
so it would always yield that block and Ruby would spin at 100%. Now we
require all callers to say what they want to listen for. This drops
CPU down to almost nothing.

See GH-832
This commit is contained in:
Mitchell Hashimoto 2012-06-01 17:00:50 +02:00
parent 903fd3acdc
commit 1a6ae81aa9
4 changed files with 28 additions and 4 deletions

View File

@ -314,6 +314,9 @@ module Vagrant
@logger.info("Interrupted.") @logger.info("Interrupted.")
end end
# Append in the options for subprocess
command << { :notify => [:stdout, :stderr] }
Util::Busy.busy(int_callback) do Util::Busy.busy(int_callback) do
Subprocess.execute(@vboxmanage_path, *command, &block) Subprocess.execute(@vboxmanage_path, *command, &block)
end end

View File

@ -63,7 +63,7 @@ module Vagrant
end end
end end
Vagrant::Util::Subprocess.execute(command, &block) Vagrant::Util::Subprocess.execute(command, :notify => [:stdout, :stderr], &block)
end end
# Run a shell command within the VM. The command will run within a # Run a shell command within the VM. The command will run within a

View File

@ -29,8 +29,27 @@ module Vagrant
def execute def execute
# Get the timeout, if we have one # Get the timeout, if we have one
timeout = @options[:timeout] timeout = @options[:timeout]
# Get the working directory
workdir = @options[:workdir] || Dir.pwd workdir = @options[:workdir] || Dir.pwd
# Get what we're interested in being notified about
notify = @options[:notify] || []
notify = [notify] if !notify.is_a?(Array)
if notify.empty? && block_given?
# If a block is given, subscribers must be given, otherwise the
# block is never called. This is usually NOT what you want, so this
# is an error.
message = "A list of notify subscriptions must be given if a block is given"
raise ArgumentError, message
end
# Let's get some more useful booleans that we access a lot so
# we're not constantly calling an `include` check
notify_stderr = notify.include?(:stderr)
notify_stdin = notify.include?(:stdin)
notify_stdout = notify.include?(:stdout)
# Build the ChildProcess # Build the ChildProcess
@logger.info("Starting process: #{@command.inspect}") @logger.info("Starting process: #{@command.inspect}")
process = ChildProcess.build(*@command) process = ChildProcess.build(*@command)
@ -80,7 +99,8 @@ module Vagrant
@logger.debug("Selecting on IO") @logger.debug("Selecting on IO")
while true while true
results = IO.select([stdout, stderr], [process.io.stdin], nil, timeout || 5) writers = notify_stdin ? [process.io.stdin] : []
results = IO.select([stdout, stderr], writers, nil, timeout || 5)
readers, writers = results readers, writers = results
# Check if we have exceeded our timeout # Check if we have exceeded our timeout

View File

@ -51,7 +51,8 @@ module Acceptance
options = argN.last.is_a?(Hash) ? argN.pop : {} options = argN.last.is_a?(Hash) ? argN.pop : {}
options = { options = {
:workdir => @workdir, :workdir => @workdir,
:env => @env :env => @env,
:notify => [:stdin, :stderr, :stdout]
}.merge(options) }.merge(options)
# Add the options to be passed on # Add the options to be passed on
@ -59,7 +60,7 @@ module Acceptance
# Execute, logging out the stdout/stderr as we get it # Execute, logging out the stdout/stderr as we get it
@logger.info("Executing: #{[command].concat(argN).inspect}") @logger.info("Executing: #{[command].concat(argN).inspect}")
Vagrant::Util::Subprocess.execute(command, *argN) do |type, data| Vagrant::Util::Subprocess.execute(command *argN) do |type, data|
@logger.debug("#{type}: #{data}") if type == :stdout || type == :stderr @logger.debug("#{type}: #{data}") if type == :stdout || type == :stderr
yield type, data if block_given? yield type, data if block_given?
end end