lib/tork/master.rb in tork-18.2.4 vs lib/tork/master.rb in tork-19.0.0
- old
+ new
@@ -2,41 +2,48 @@
require 'tork/config'
module Tork
class Master < Server
+ # detect the number of CPUs available in the system
+ # http://stackoverflow.com/questions/891537#6420817
+ MAX_CONCURRENT_WORKERS = [
+ 'fgrep -c processor /proc/cpuinfo', # Linux
+ 'sysctl -n hw.ncpu', # BSD
+ 'hwprefs cpu_count', # Darwin 9
+ 'hwprefs thread_count', # Darwin 10
+ ].
+ map {|cmd| `#{cmd} 2>/dev/null`.to_i }.push(1).max
+
def initialize
super
+ Tork.config :master
+ send @clients, [:absorb]
- @worker_number_pool = (0 ... Config.max_forked_workers).to_a
+ @worker_number_pool = (0 ... MAX_CONCURRENT_WORKERS).to_a
@command_by_worker_pid = {}
end
- def load paths, files
- $LOAD_PATH.unshift(*paths)
-
- @overhead_files = files.each do |file|
- branch, leaf = File.split(file)
- file = leaf if paths.include? branch
- require file.sub(/\.rb$/, '')
- end
-
- @client.send @command
+ def loop
+ super
+ ensure
+ stop :SIGKILL
end
def test test_file, line_numbers
- return if @overhead_files.include? test_file
-
# throttle forking rate to meet the maximum concurrent workers limit
- sleep 1 until @command_by_worker_pid.size < Config.max_forked_workers
+ sleep 1 until @command_by_worker_pid.size < @worker_number_pool.size
log_file = test_file + '.log'
worker_number = @worker_number_pool.shift
+ @command.push log_file, worker_number
- Config.before_fork_hooks.each do |hook|
- hook.call test_file, line_numbers, log_file, worker_number
- end
+ $tork_test_file = test_file
+ $tork_line_numbers = line_numbers
+ $tork_log_file = log_file
+ $tork_worker_number = worker_number
+ Tork.config :onfork
worker_pid = fork do
# make the process title Test::Unit friendly and ps(1) searchable
$0 = "tork-worker[#{worker_number}] #{test_file}"
@@ -48,43 +55,36 @@
# capture test output in log file because tests are run in parallel
# which makes it difficult to understand interleaved output thereof
STDERR.reopen(STDOUT.reopen(log_file, 'w')).sync = true
- Config.after_fork_hooks.each do |hook|
- hook.call test_file, line_numbers, log_file, worker_number
- end
+ Tork.config :worker
# after loading the user's test file, the at_exit() hook of the user's
# testing framework will take care of running the tests and reflecting
# any failures in the worker process' exit status, which will then be
# handled by the reaping thread registered in the master process (below)
Kernel.load test_file if test_file.end_with? '.rb'
end
- @command_by_worker_pid[worker_pid] = @command.push(log_file, worker_number)
- @client.send @command
+ @command_by_worker_pid[worker_pid] = @command
+ send @clients, @command
# wait for the worker to finish and report its status to the client
- Thread.new do # the reaping thread
- worker_status = Process.wait2(worker_pid).last
- command = @command_by_worker_pid.delete(worker_pid)
+ Thread.new(worker_pid) do |pid| # the reaping thread
+ status = Process.wait2(pid).last
+ command = @command_by_worker_pid.delete(pid)
@worker_number_pool.push command.last
- command[0] = if worker_status.success? then :pass else :fail end
- @client.send command.push(worker_status.to_i, worker_status.inspect)
+ command[0] = status.success? && :pass || :fail
+ send @clients, command.push(status.to_i, status.inspect)
end
end
- def stop
+ def stop signal=:SIGTERM
# the reaping threads registered above will reap these killed workers
- Process.kill :SIGTERM, *@command_by_worker_pid.keys.map {|pid| -pid }
+ Process.kill signal, *@command_by_worker_pid.keys.map {|pid| -pid }
rescue ArgumentError, SystemCallError
# some workers might have already exited before we sent them the signal
- end
-
- def quit
- stop
- super
end
end
end