feature request: mock --timeout

Michael E Brown Michael_E_Brown at dell.com
Thu Apr 19 06:14:32 UTC 2007


On Mon, Apr 16, 2007 at 01:07:52PM -0500, Michael E Brown wrote:
> On Mon, Apr 16, 2007 at 12:50:11PM -0500, Clark Williams wrote:
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA1
> > 
> > Matt Domsch wrote:
> > > I'd like to make a feature request for mock: the ability for it to
> > > determine a job has taken too long and kill it.  mock --timeout N (with N
> > > in minutes) is the UI I'm picturing.
> > > 
> > > 
> > > I've been doing these mass rebuilds for a while.  Every so often we'll
> > > wind up with a package with the halting problem - it continues to run,
> > > or not, but it doesn't ever finish building either.  Ever.  Several
> > > days later, it's still going, but not making progress.
> > > 
> > > Sure, some jobs, like the kernel, openoffice, glibc, etc. can take a
> > > good number of hours.  But even those don't run for days.  The latest
> > > culprits was a few perl modules that ran for >2 days with no end in
> > > sight.
> > > 
> > 
> > File an RFE BZ on it and I'll look at it.
> 
> I have some python code from another project that does exactly this. I
> can drop it in. I'll send a patch for review.

here is my previous code to call an external command with a timeout.
I'll do a patch when I get a minute, but this should give a good idea:


# helper class & functions for executeCommand()
# User should handle this if they specify a timeout
class commandTimeoutExpired(Exception): pass

# the problem with os.system() is that the command that is run gets any 
# keyboard input and/or signals. This means that <CTRL>-C interrupts the 
# sub-program instead of the python program. This helper function fixes
# that.
# It also allows us to set up a maximum timeout before all children are
# killed
def executeCommand(cmd, timeout=0):
    class alarmExc(Exception): pass
    def alarmhandler(signum,stackframe):
        raise alarmExc("timeout expired")

    pid = os.fork()
    if pid:
        #parent
        rpid = ret = 0
        oldhandler=signal.signal(signal.SIGALRM,alarmhandler)
        starttime = time.time()
        prevTimeout = signal.alarm(timeout)
        try:
            (rpid, ret) = os.waitpid(pid, 0)
            signal.alarm(0)
            signal.signal(signal.SIGALRM,oldhandler)
            if prevTimeout:
                passed = time.time() - starttime
                signal.alarm(math.ceil(prevTimeout - passed))
        except alarmExc:
            os.kill(-pid, signal.SIGTERM)
            time.sleep(1)
            os.kill(-pid, signal.SIGKILL)
            (rpid, ret) = os.waitpid(pid, 0)
            signal.signal(signal.SIGALRM,oldhandler)
            if prevTimeout:
                passed = time.time() - starttime
                signal.alarm(max(math.ceil(prevTimeout - passed), 1))
            raise commandTimeoutExpired( "Specified timeout of %s
seconds expired before command finished. Command was: %s"
                    % (timeout, cmd)
                    )

        # mask and return just return value
        return (ret & 0xFF00) >> 8
    else:
        #child
        os.setpgrp()  # become process group leader so that we can kill
all our children
        ret = os.system(cmd)
        os._exit( (ret & 0xFF00) >> 8 )




More information about the Fedora-buildsys-list mailing list