#!/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 [ ..]\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()