<%
#!/usr/bin/env ruby
## kill some warnings about writable directories
$VERBOSE=nil
# we want to parse input, right?
require 'optparse'
## global options (which can and will be changed)
@@options = {
:runtime => "01:00:00",
:total_time => 0,
:threadlist => [],
}
def parse_input()
ARGV.options do |opts|
opts.banner = "Usage: #{$0} [options] <thread names>"
opts.separator "Threadeds spawning threads, oh my!"
opts.separator ""
opts.separator "Options:"
opts.on("-h", "--help", "show this message") {
puts opts
exit
}
opts.on("-v", "--version", "show version details") {
version = `grep -m 1 "#(@)" #{$0} | awk '{printf("version: %s (%s)",$3,$2)}'`
puts version
exit
}
opts.on("--duration=HH:MM:SS", String, "specify how long to run test (default: #{@@options[:runtime]})") { |@@options[:runtime]| }
opts.parse!
end
## validate time
hours, mins, secs = @@options[:runtime].to_s.split(":")
if hours.nil? or mins.nil? or secs.nil?
puts "ERROR -- Invalid time format!"
exit 1
end
@@options[:total_time] = (hours.to_i * 60 * 60) + (mins.to_i * 60) + secs.to_i
## thread list, anyone?
if ARGV.length < 1
puts "ERROR! No thread names specified!"
exit 1
else
@@options[:threadlist] = ARGV
end
end
@threads = []
@start_time = Time.now
## trap ctrl-c
trap("INT") { threadDestroyAll() }
def newPass(threadname)
## create a new thread and add it to @threads
@threads << Thread.new(threadname) { |myThread|
## trap that CTRL-C
trap("INT") { threadDestroyAll() }
## name thread to that of name given. easier management
Thread.current[:name] = "#{myThread}"
## Stuff for thread to do goes here.
}
end
## this is triggered via CTRL-C trap above
# kill all threads and exit
def threadDestroyAll()
puts "***************************"
puts "** Killing all processes **"
puts "***************************"
@threads.each { |thread| thread.kill }
sleep 2
Thread.main.kill
end
## needed a way to watch over all the baby threads
# this will cycle through all threads, gathering a list of
#+ those that are still running (and their names, which are that of the client)
#+ any missing clients are then restarted.
def threadOverlord(threads)
threadList = activeThreads = deadThreads = []
threadList = @@options[:threadlist]
threads.each { |thread| activeThreads << thread[:name] if thread.alive? and keepGoing() }
## restart baby threads that have died?
# if time limit has been reached, that is a no
if keepGoing()
deadThreads = threadList - activeThreads
deadThreads.each { |threadname| newPass(threadname) }
end
activeThreads = deadThreads = threadList = nil
end
## parent thread
# this is just to trigger threadOverlord every X seconds
#+ and check on the health of client threads
def statusThread()
statusT = Thread.new {
Thread.current[:name] = "Overlord"
loop do
threadOverlord(@threads)
sleep 15
break if !keepGoing()
end
}
statusT.join
end
## returns true if there is still time remaining
def keepGoing()
return true if Time.now.to_i - @start_time.to_i < @@options[:total_time].to_i
false
end
parse_input()
statusThread
%>