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.

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}"