G
Greg Kuperberg
I want to run subprocesses with limits on the execution time and the
output size of the subprocess. If the subprocess exceeds limits, then
the parent should kill it gracefully (SIGTERM rather than SIGKILL). This
is a useful safety mechanism if you have a CGI interface that starts
jobs per user request.
As a result of this effort, I have a comment and a question:
(1) I don't think that process control is thought through very well
in Python. Do I really need os, popen2, fcntl, signal, and select?
If so, it is not nearly as attractive as, for example, using the cgi
module to process cgi input.
(2) I still don't know if I am doing this right. I didn't completely
understand the recent discussion about the os.kill() function, and in
general I am not sure if what I have is safe. Is it okay?
-----------------------------------
import os,sys,time,popen2,fcntl,signal,select,exceptions
class ProcError(exceptions.Exception):
def __init__(me,type):
if type == 'space': me.args = 'Space limit exceeded!'
elif type == 'time': me.args = 'Time limit exceeded!'
else: me.args = 'Unknown error'
def subprocess(command,timeout=None,spaceout=None):
proc = popen2.Popen4(command)
pout = proc.fromchild
proc.tochild.close()
output = ''
try:
if timeout:
fcntl.fcntl(pout,fcntl.F_SETFL,os.O_NONBLOCK)
endtime = time.time() + timeout
while 1:
timeleft = endtime - time.time()
if timeleft <= 0: raise ProcError,'time'
(ready,toss,toss) = select.select([pout],[],[],timeleft)
if not ready: raise ProcError,'time'
if spaceout:
output += pout.read(spaceout-len(output))
if len(output) >= spaceout: raise ProcError,'space'
else:
output += pout.read()
if proc.poll() >= 0: break
else:
if spaceout: output = pout.read(spaceout)
else: output = pout.read()
if proc.poll(): raise ProcError,'space'
except ProcError:
print sys.exc_value # Debug
os.kill(proc.pid,signal.SIGTERM)
return output
output size of the subprocess. If the subprocess exceeds limits, then
the parent should kill it gracefully (SIGTERM rather than SIGKILL). This
is a useful safety mechanism if you have a CGI interface that starts
jobs per user request.
As a result of this effort, I have a comment and a question:
(1) I don't think that process control is thought through very well
in Python. Do I really need os, popen2, fcntl, signal, and select?
If so, it is not nearly as attractive as, for example, using the cgi
module to process cgi input.
(2) I still don't know if I am doing this right. I didn't completely
understand the recent discussion about the os.kill() function, and in
general I am not sure if what I have is safe. Is it okay?
-----------------------------------
import os,sys,time,popen2,fcntl,signal,select,exceptions
class ProcError(exceptions.Exception):
def __init__(me,type):
if type == 'space': me.args = 'Space limit exceeded!'
elif type == 'time': me.args = 'Time limit exceeded!'
else: me.args = 'Unknown error'
def subprocess(command,timeout=None,spaceout=None):
proc = popen2.Popen4(command)
pout = proc.fromchild
proc.tochild.close()
output = ''
try:
if timeout:
fcntl.fcntl(pout,fcntl.F_SETFL,os.O_NONBLOCK)
endtime = time.time() + timeout
while 1:
timeleft = endtime - time.time()
if timeleft <= 0: raise ProcError,'time'
(ready,toss,toss) = select.select([pout],[],[],timeleft)
if not ready: raise ProcError,'time'
if spaceout:
output += pout.read(spaceout-len(output))
if len(output) >= spaceout: raise ProcError,'space'
else:
output += pout.read()
if proc.poll() >= 0: break
else:
if spaceout: output = pout.read(spaceout)
else: output = pout.read()
if proc.poll(): raise ProcError,'space'
except ProcError:
print sys.exc_value # Debug
os.kill(proc.pid,signal.SIGTERM)
return output