Snippets
Created by
Peter Bui
last modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | #!/usr/bin/env python2.7
import sys
import getopt
import signal
import os
import errno
import time
SECONDS=10
VERBOSE=False
#Usage function
def usage(status=0):
print '''Usage: timeout.py [-t SECONDS] command...
Options:
-t SECONDS SECONDS duration before killing command (default is 10 seconds)
-v Display verbose debugging output
'''.format(os.path.basename(sys.argv[0]))
sys.exit(status)
def debug(message, *args):
if VERBOSE:
print message.format(*args)
def handler(signum, frame):
print 'Signal handler called with signal', signum
raise IOError("Alarm has been triggered after 1 second")
#Parse command line options
try:
opts, args = getopt.getopt(sys.argv[1:], "hvt:")
except getopt.GetoptError as e:
print e
usage(1)
for opt, arg in opts:
if opt == '-v':
VERBOSE=True
elif opt == '-h':
usage(1)
elif opt == '-t':
SECONDS=int(arg)
else:
usage(1)
COMMAND=" ".join(args)
debug('Executing "{}" for at most {} seconds...', COMMAND, SECONDS)
try:
pid = os.fork()
debug('Forking...', COMMAND, SECONDS)
except OSError as e:
print 'Fork failed: {}'.format(e)
sys.exit(1)
try:
signal.signal(signal.SIGALRM, handler)
signal.alarm(SECONDS)
debug('Enabling Alarm...', COMMAND, SECONDS)
except OSError as e:
print 'Alarm failed: {}'.format(e)
sys.exit(1)
try:
newpid, status = os.wait()
debug('Waiting: ', COMMAND, SECONDS)
except OSError as e:
if e.errno == errno.EINTR:
pid, status=os.wait()
else:
print e
except IOError as e:
#If alarm triggered, then kill it
try:
os.kill(pid, status)
os.kill(pid, sig)
debug('Killing PID...', COMMAND, SECONDS)
except OSError as e:
print 'Killed failed: {}'.format(e)
sys.exit(1)
if pid == 0: #child
try:
os.execlp(COMMAND,COMMAND)
debug('Execing...', COMMAND, SECONDS)
except OSError as e:
print 'Execing failed: {}'.format(e)
sys.exit(1)
except IOError as e:
#If alarm triggered, then kill it
try:
os.kill(pid, status)
os.kill(pid, sig)
debug('Killing PID...', COMMAND, SECONDS)
except OSError as e:
print 'Killed failed: {}'.format(e)
sys.exit(1)
try:
signal.alarm(0) #disable alarm
debug('Disabling Alaram...', COMMAND, SECONDS)
except OSError as e:
print 'Alarm failed: {}'.format(e)
sys.exit(1)
except IOError as e:
#If alarm triggered, then kill it
try:
os.kill(pid, status)
os.kill(pid, sig)
debug('Killing PID...', COMMAND, SECONDS)
except OSError as e:
print 'Killed failed: {}'.format(e)
sys.exit(1)
|
Comments (1)
You can clone a snippet to your computer for local editing. Learn more.
After you fork, you should do the following:
Child
Parent
While waiting for the child, two things can happen:
The child exits within the time frame, so the the parent will receive the pid and status and should exit with that status
The child runs too long, so the alarm will interrupt the parent. When this happens, the handler should kill the child process.
If the parent killed the child, then it must wait again for it.