91 lines
2.1 KiB
Python
91 lines
2.1 KiB
Python
#!/usr/bin/python3
|
|
|
|
import datetime
|
|
import os
|
|
import select
|
|
import subprocess
|
|
import sys
|
|
import _thread
|
|
|
|
proc = None
|
|
|
|
def run_child(args, fd):
|
|
global proc
|
|
|
|
f = os.fdopen(fd, 'w')
|
|
proc = subprocess.Popen(args)
|
|
|
|
# Tell main thread to continue
|
|
f.write('a')
|
|
f.flush()
|
|
|
|
f.write(str(proc.wait()))
|
|
|
|
def main():
|
|
global proc
|
|
|
|
def usage():
|
|
sys.stderr.write('Usage: %s <max_minutes> <cmd> [<args> ..]\n' % sys.argv[0])
|
|
sys.exit(1)
|
|
|
|
if len(sys.argv) < 3:
|
|
usage()
|
|
|
|
try:
|
|
max_mins = int(sys.argv[1])
|
|
except:
|
|
usage()
|
|
|
|
max_days = max_mins / (24 * 60)
|
|
max_seconds = (max_mins % (max_days * 24 * 60) if max_days > 0 else max_mins) * 60
|
|
|
|
start = datetime.datetime.now()
|
|
|
|
(rfd, wfd) = os.pipe()
|
|
f = os.fdopen(rfd, 'r')
|
|
_thread.start_new_thread(run_child, (sys.argv[2:], wfd))
|
|
|
|
# Make sure that we have a process before continuing
|
|
f.read(1)
|
|
|
|
target_timeout = 60
|
|
|
|
last_target_timeout = target_timeout
|
|
timeout = target_timeout
|
|
terminated = False
|
|
laststart = None
|
|
|
|
while True:
|
|
if target_timeout != last_target_timeout:
|
|
last_target_timeout = target_timeout
|
|
timeout = target_timeout
|
|
elif laststart is not None:
|
|
now = datetime.datetime.now()
|
|
timeout = timeout - (((now - laststart).total_seconds() - target_timeout) / 4)
|
|
laststart = datetime.datetime.now()
|
|
|
|
(r, w, x) = select.select([f], [], [], timeout)
|
|
if len(r) != 0:
|
|
sys.exit(int(f.read()))
|
|
|
|
duration = datetime.datetime.now() - start
|
|
|
|
if not terminated:
|
|
sys.stdout.write('*** KEEP ALIVE MARKER ***\n')
|
|
sys.stdout.write('Total duration: %s\n' % str(duration))
|
|
sys.stdout.flush()
|
|
|
|
if (duration.days >= max_days and duration.seconds >= max_seconds) or terminated:
|
|
if not terminated:
|
|
sys.stderr.write('Process max time exceeded, attempting to terminate\n')
|
|
sys.stderr.flush()
|
|
proc.terminate()
|
|
terminated = True
|
|
target_timeout = 15
|
|
else:
|
|
sys.stderr.write('Attempting to kill process\n')
|
|
sys.stderr.flush()
|
|
proc.kill()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|