Let's say I have a ruby script which calls system() to run some
arbitrary program. Since that program might spiral off into some evil
infinite-loop, is there some way for me to say "execute this, but for
no longer than 2 seconds of CPU time"? In the C-world I might use
something like setrlimit, but I'm not sure how easy that would be to
do from within a ruby script.
Note that I don't want to limit the CPU time of the script itself. I
just want to limit the CPU time for specific applications that I
execute via system().
···
--
Garance Alistair Drosehn = drosihn@gmail.com
Senior Systems Programmer or gad@FreeBSD.org
Rensselaer Polytechnic Institute; Troy, NY; USA
maybe something like
harp:~ > cat a.rb
require 'timeout'
def spawn cmd, sec
pid = fork{ system cmd }
begin
Timeout::timeout(sec){ Process::waitpid2(pid).last }
rescue Timeout::Error => e
Process::kill 'TERM', pid rescue nil
Process::kill 'KILL', pid rescue nil
Process::waitpid2(pid).last
end
end
p(spawn('sleep 2', 4))
p(spawn('sleep 4', 2))
harp:~ > ruby a.rb
#<Process::Status: pid=6872,exited(0)>
#<Process::Status: pid=6874,signaled(SIGTERM=15)>
hth.
-a
···
On Wed, 15 Jun 2005, Garance A Drosehn wrote:
Let's say I have a ruby script which calls system() to run some
arbitrary program. Since that program might spiral off into some evil
infinite-loop, is there some way for me to say "execute this, but for
no longer than 2 seconds of CPU time"? In the C-world I might use
something like setrlimit, but I'm not sure how easy that would be to
do from within a ruby script.
Note that I don't want to limit the CPU time of the script itself. I
just want to limit the CPU time for specific applications that I
execute via system().
--
email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso
===============================================================================
I'm going to give a general Unix programming answer and then some
comments about doing it in Ruby.
The basic technique is to fork a child process, have the child
process use setrlimit() to establish the resource limitations and
then have the child fork *again*. The "grandchild" process then
does the actual work subject to the limitations set by the child
process. The child process can exit once the grandchild has started.
This works because resource limits are inherited across a fork.
A quick and dirty way to accomplish all this in Ruby:
system(%q{
echo $$; # show the current pid
ulimit -a; # show the current limits
ulimit -t 1; # change the CPU time limit to 1 sec
sh -c 'echo $$; ulimit -a' # start a new process and show limits
})
Note, you can't use this technique to change the limits of the
current process because system does its thing in a child process, not
in the process that called system.
If you wanted to do all this within Ruby (i.e. without using system)
you are stuck because the standard Process class doesn't support
setrlimit (and the related getrlimit). Google has a link to an
RAA project that no longer exists at RAA called 'resource' that
looks like it implemented these functions. Maybe someone else is
aware of a similar project. If you had setrlimit you could do
something like:
puts "main: #{Process.pid}"
unless child_pid = fork
puts "child: #{Process.pid}"
# setrlimit(....)
unless grand_child = fork
puts "grandchild: #{Process.pid}"
puts "grandchild: doing the work"
exit(0)
end
puts "grandchild: exited: #{Process.wait}"
exit(0)
end
puts "child: exited: #{Process.wait}"
···
On Jun 14, 2005, at 10:19 PM, Garance A Drosehn wrote:
Let's say I have a ruby script which calls system() to run some
arbitrary program. Since that program might spiral off into some evil
infinite-loop, is there some way for me to say "execute this, but for
no longer than 2 seconds of CPU time"? In the C-world I might use
something like setrlimit, but I'm not sure how easy that would be to
do from within a ruby script.
In article <97880ae0506141918e56d386@mail.gmail.com>,
Garance A Drosehn <drosihn@gmail.com> writes:
Let's say I have a ruby script which calls system() to run some
arbitrary program. Since that program might spiral off into some evil
infinite-loop, is there some way for me to say "execute this, but for
no longer than 2 seconds of CPU time"? In the C-world I might use
something like setrlimit, but I'm not sure how easy that would be to
do from within a ruby script.
Note that I don't want to limit the CPU time of the script itself. I
just want to limit the CPU time for specific applications that I
execute via system().
Ruby 1.9 has Process.setrlimit (and Process.getrlimit).
% ruby -e 'Process.wait fork { Process.setrlimit Process::RLIMIT_CPU, 2, 2; exec "yes > /dev/null" }'
···
--
Tanaka Akira
Hi,
At Wed, 15 Jun 2005 12:40:47 +0900,
Ara.T.Howard wrote in [ruby-talk:145444]:
> Let's say I have a ruby script which calls system() to run some
> arbitrary program. Since that program might spiral off into some evil
> infinite-loop, is there some way for me to say "execute this, but for
> no longer than 2 seconds of CPU time"? In the C-world I might use
> something like setrlimit, but I'm not sure how easy that would be to
> do from within a ruby script.
Resouce module is in "rough".
<http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/rough/ext/resource/>
maybe something like
harp:~ > cat a.rb
require 'timeout'
def spawn cmd, sec
pid = fork{ system cmd }
begin
Timeout::timeout(sec){ Process::waitpid2(pid).last }
rescue Timeout::Error => e
Process::kill 'TERM', pid rescue nil
You should give a chance to terminate gently to the child process, I
guess.
···
Process::kill 'KILL', pid rescue nil
--
Nobu Nakada
never used it, but i did notice "rlimit" port in RPAbase with
#getrlimit
Tanaka Akira wrote:
···
In article <97880ae0506141918e56d386@mail.gmail.com>,
Garance A Drosehn <drosihn@gmail.com> writes:
> Let's say I have a ruby script which calls system() to run some
> arbitrary program. Since that program might spiral off into some evil
> infinite-loop, is there some way for me to say "execute this, but for
> no longer than 2 seconds of CPU time"? In the C-world I might use
> something like setrlimit, but I'm not sure how easy that would be to
> do from within a ruby script.
>
> Note that I don't want to limit the CPU time of the script itself. I
> just want to limit the CPU time for specific applications that I
> execute via system().
Ruby 1.9 has Process.setrlimit (and Process.getrlimit).
% ruby -e 'Process.wait fork { Process.setrlimit Process::RLIMIT_CPU, 2, 2; exec "yes > /dev/null" }'
--
Tanaka Akira
yes, very true. in 'real-life' the code from my lib is
module Util
···
On Wed, 15 Jun 2005, nobuyoshi nakada wrote:
You should give a chance to terminate gently to the child process, I
guess.
Process::kill 'KILL', pid rescue nil
#
# returns true if pid is running, false otherwise
#
def alive pid
#--{{
pid = Integer("#{ pid }")
begin
Process::kill 0, pid
true
rescue Errno::ESRCH
false
end
#--}}}
end
alias alive? alive
#
# brutally shut down a process. opts can contain the keys 'signals' which
# should be a list of signals used to send to the process and the key
# 'suspend' which is the amount of time to wait after firing each signal
# before seeing if the process is dead. the defaults are %w(TERM QUIT KILL)
# and 4 respectively
#
def maim(pid, opts = {})
#--{{{
sigs = Util::getopt 'signals', opts, %w(SIGTERM SIGQUIT SIGKILL)
suspend = Util::getopt 'suspend', opts, 4
pid = Integer("#{ pid }")
existed = false
sigs.each do |sig|
begin
Process::kill(sig, pid)
existed = true
rescue Errno::ESRCH
unless existed
return nil
else
return true
end
end
sleep 0.1
return true unless Util::alive?(pid)
sleep suspend
return true unless Util::alive?(pid)
end
return(not alive?(pid))
#--}}}
end
#
# look up key in hash as key, then string of key, then intern of key -
# returning the value or, if key is not found, nil or default
#
def getopt opt, hash, default = nil
#--{{{
key = opt
return hash[key] if hash.has_key? key
key = "#{ key }"
return hash[key] if hash.has_key? key
key = key.intern
return hash[key] if hash.has_key? key
return default
#--}}}
end
end
but that's not so nice to post
-a
--
email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso
===============================================================================