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