Limiting Execution Time in a Shell, Part II
A year ago, I thought I worked around the halting problem. I have students’ code that I need to grade, but sometimes they slip in an infinite loop. This really messes up automated grading. I wrote a shell script that would run their code for X seconds, killing their process if necessary. Sadly, I went to use that script again this semester, but it would hang when I invoked it across SSH:
ssh tester@localhost "cd student/folder && forn 30 theirs.exe"
The script works fine when not run across SSH. I don’t know what the problem is. Instead of asking the Internet for help, I just rewrote the script in Ruby, and it works just fine across SSH:
#!/usr/bin/env ruby # ---------------------------------------------------------------------------- # FILE: forn # AUTHOR: Chris Johnson # DATE: Dec 03 2014 # # Executes a command with a time limit. If the command takes longer than the # specified number of seconds, it is killed and status 37 is returned. # Otherwise, the exit status of the command is returned. # ---------------------------------------------------------------------------- require 'timeout' if ARGV.length < 1 puts "Usage: forn delay-in-seconds command arg1 arg2 ..." exit 1 end delay = ARGV[0].to_i ARGV.shift # Start command, but kill it if delay elapses. pid = Process.spawn(ARGV.shelljoin) begin Timeout.timeout(delay) do Process.wait pid exit $?.exitstatus end rescue Timeout::Error puts "Uh oh. Execution timed out after #{delay} second#{delay == 1 ? '' : 's'}." Process.kill(:SIGTERM, pid) exit 37 end