1 #!/usr/bin/python 2 3 import common 4 import sys, os, signal, time, subprocess, fcntl 5 6 logdir = sys.argv[1] 7 stdout_start = int(sys.argv[2]) # number of bytes we can skip on stdout 8 stderr_start = int(sys.argv[3]) # nubmer of bytes we can skip on stderr 9 # TODO (crosbug.com/38224)- sbasi: Remove extra logging. 10 stderr = open(os.path.join(logdir, 'stderr'), 'a', 0) 11 12 print >> stderr, 'Entered autotestd_monitor.' 13 # if any of our tail processes die, the monitor should die too 14 def kill_self(signum, frame): 15 os.kill(os.getpid(), signal.SIGTERM) 16 signal.signal(signal.SIGCHLD, kill_self) 17 18 devnull = open(os.devnull, 'w') 19 20 # launch some tail processes to pump the std* streams 21 def launch_tail(filename, outstream, start): 22 path = os.path.join(logdir, filename) 23 argv = ['tail', '--retry', '--follow=name', '--bytes=+%d' % start, path] 24 # stdout=sys.stdout fails on pre-2.5 python (bug in subprocess module) 25 if outstream != subprocess.PIPE and outstream.fileno() == 1: 26 return subprocess.Popen(argv, stderr=devnull) 27 else: 28 return subprocess.Popen(argv, stdout=outstream, stderr=devnull) 29 stdout_pump = launch_tail('stdout', sys.stdout, stdout_start) 30 stderr_pump = launch_tail('stderr', sys.stderr, stderr_start) 31 32 print >> stderr, 'Finished launching tail subprocesses.' 33 34 # wait for logdir/started to exist to be sure autotestd is started 35 start_time = time.time() 36 started_file_path = os.path.join(logdir, 'started') 37 while not os.path.exists(started_file_path): 38 time.sleep(1) 39 if time.time() - start_time >= 30: 40 raise Exception("autotestd failed to start in %s" % logdir) 41 42 print >> stderr, 'Finished waiting on autotestd to start.' 43 44 # watch the exit code file for an exit 45 exit_code_file = open(os.path.join(logdir, 'exit_code')) 46 fcntl.flock(exit_code_file, fcntl.LOCK_EX) 47 print >> stderr, 'Got lock of exit_code_file.' 48 try: 49 exit_code = exit_code_file.read() 50 if len(exit_code) != 4: 51 exit_code = -signal.SIGKILL # autotestd was nuked 52 else: 53 exit_code = int(exit_code) 54 finally: 55 fcntl.flock(exit_code_file, fcntl.LOCK_UN) 56 exit_code_file.close() 57 print >> stderr, 'Released lock of exit_code_file and closed it.' 58 59 # tail runs in 1s polling loop, so give them a chance to finish 60 time.sleep(2) 61 62 print >> stderr, 'Killing child processes.' 63 # clear the SIGCHLD handler so that killing the tails doesn't kill us 64 signal.signal(signal.SIGCHLD, signal.SIG_DFL) 65 os.kill(stdout_pump.pid, signal.SIGTERM) 66 os.kill(stderr_pump.pid, signal.SIGTERM) 67 68 # exit (with the same code as autotestd) 69 sys.exit(exit_code) 70