Running a subprocess on a "leash"

Greg Kuperberg greg at conifold.math.ucdavis.edu
Tue Oct 7 20:07:46 EDT 2003


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
-- 
  /\  Greg Kuperberg (UC Davis)
 /  \
 \  / Visit the Math ArXiv Front at http://front.math.ucdavis.edu/
  \/  * All the math that's fit to e-print *




More information about the Python-list mailing list