Skip to content

Commit

Permalink
autograde_wrapper.py improvements
Browse files Browse the repository at this point in the history
- spawn a thread that calls wait(). We are pid 1 in the container
  and need to collect all zombies, otherwise autodriver might get
  confused
- Don't double fork. it's not easy to pass the full exit status
  of autodriver through a double fork, so use os.execvp instead
  of subprocess.call. This means we have to do some of the file
  descriptor munging directly.
- Don't bother creating a temporary output file. Directly pipe
  autodriver's output to the real output file
  • Loading branch information
cg2v committed Aug 2, 2015
1 parent 2f7d76f commit d0cbc4f
Showing 1 changed file with 38 additions and 8 deletions.
46 changes: 38 additions & 8 deletions autodriver/autograde_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,61 @@
import os
import pwd
import shutil
import subprocess
import threading
#print("Running "+ str(sys.argv))

# Wait for all processes, since we are pid 1 in the container,
# terminate once the interesting process exits
class WaitLoop(object):
def __init__(self, pid=None):
self.waitfor=pid
self.status=None
def __call__(self):
try:
(np, self.status)=os.wait()
while pid is None or np != self.waitfor:
(np, self.status)=os.wait()
except OSError:
if pid:
print("Chld process {} never exited, but no more children left".format(self.waitfor))
self.status=-1

for f in os.listdir("mount"):
src=os.path.join("mount", f)
dst=os.path.join("autolab", f)
shutil.copy(src, dst)

autolabuser=pwd.getpwnam("autolab")
(r_p, w_p)=os.pipe()
pid=os.fork()
if pid == 0:
os.close(r_p)
os.setgroups([])
os.setgid(autolabuser.pw_gid)
os.setuid(autolabuser.pw_uid)
outfile=open("output/feedback", "w")
args=["autodriver"]
args.extend(sys.argv[1:])
args.append("autolab")
print("Executing "+str(args), file=outfile)
sys.exit(subprocess.call(args, stdout=outfile, stderr=outfile, close_fds=True))
(np, status)=os.waitpid(pid, 0)
if w_p != 1:
os.dup2(w_p, 1)
if w_p != 2:
os.dup2(w_p, 2)
if w_p > 2:
os.close(w_p)
os.execvp(args[0], args)
os.close(w_p)
waiter=WaitLoop(pid)
thr=threading.Thread(target=waiter)
thr.start()
rpf=os.fdopen(r_p)
shutil.copyfileobj(rpf, open("mount/feedback", "w"))
#print("Copied output")
rpf.close()
thr.join()
# if core, exit -1, else pass through code.
if status & 0xff:
if os.WIFSIGNALED(waiter.status):
status=-1
else:
status>>=8;
shutil.copy("output/feedback", "mount/feedback")
status=os.WEXITSTATUS(waiter.status)
#print("Status is {}".format(status))
sys.exit(status)

0 comments on commit d0cbc4f

Please sign in to comment.