84 lines
3.0 KiB
Plaintext
84 lines
3.0 KiB
Plaintext
|
#!/usr/bin/python2
|
||
|
|
||
|
from __future__ import absolute_import
|
||
|
from __future__ import division
|
||
|
from __future__ import print_function
|
||
|
import common
|
||
|
import sys, os, signal, time, subprocess, fcntl
|
||
|
|
||
|
|
||
|
def _print_to_file_and_flush(msg, file):
|
||
|
"""Print to the provided file, and flush after printing."""
|
||
|
print(msg, file=file)
|
||
|
file.flush()
|
||
|
|
||
|
logdir = sys.argv[1]
|
||
|
stdout_start = int(sys.argv[2]) # number of bytes we can skip on stdout
|
||
|
stderr_start = int(sys.argv[3]) # nubmer of bytes we can skip on stderr
|
||
|
# TODO (crosbug.com/38224)- sbasi: Remove extra logging.
|
||
|
stderr = open(os.path.join(logdir, 'stderr'), 'a', buffering=2)
|
||
|
|
||
|
_print_to_file_and_flush('Entered autotestd_monitor.', file=stderr)
|
||
|
|
||
|
# if any of our tail processes die, the monitor should die too
|
||
|
def kill_self(signum, frame):
|
||
|
os.kill(os.getpid(), signal.SIGTERM)
|
||
|
signal.signal(signal.SIGCHLD, kill_self)
|
||
|
|
||
|
devnull = open(os.devnull, 'w')
|
||
|
|
||
|
# launch some tail processes to pump the std* streams
|
||
|
def launch_tail(filename, outstream, start):
|
||
|
path = os.path.join(logdir, filename)
|
||
|
argv = ['tail', '--retry', '--follow=name', '--bytes=+%d' % start, path]
|
||
|
# stdout=sys.stdout fails on pre-2.5 python (bug in subprocess module)
|
||
|
if outstream != subprocess.PIPE and outstream.fileno() == 1:
|
||
|
return subprocess.Popen(argv, stderr=devnull)
|
||
|
else:
|
||
|
return subprocess.Popen(argv, stdout=outstream, stderr=devnull)
|
||
|
stdout_pump = launch_tail('stdout', sys.stdout, stdout_start)
|
||
|
stderr_pump = launch_tail('stderr', sys.stderr, stderr_start)
|
||
|
|
||
|
_print_to_file_and_flush('Finished launching tail subprocesses.', file=stderr)
|
||
|
# wait for logdir/started to exist to be sure autotestd is started
|
||
|
start_time = time.time()
|
||
|
started_file_path = os.path.join(logdir, 'started')
|
||
|
while not os.path.exists(started_file_path):
|
||
|
time.sleep(1)
|
||
|
if time.time() - start_time >= 30:
|
||
|
raise Exception("autotestd failed to start in %s" % logdir)
|
||
|
|
||
|
_print_to_file_and_flush('Finished waiting on autotestd to start.',
|
||
|
file=stderr)
|
||
|
|
||
|
# watch the exit code file for an exit
|
||
|
exit_code_file = open(os.path.join(logdir, 'exit_code'))
|
||
|
fcntl.flock(exit_code_file, fcntl.LOCK_EX)
|
||
|
_print_to_file_and_flush('Got lock of exit_code_file.', file=stderr)
|
||
|
|
||
|
try:
|
||
|
exit_code = exit_code_file.read()
|
||
|
if len(exit_code) != 4:
|
||
|
exit_code = -signal.SIGKILL # autotestd was nuked
|
||
|
else:
|
||
|
exit_code = int(exit_code)
|
||
|
finally:
|
||
|
fcntl.flock(exit_code_file, fcntl.LOCK_UN)
|
||
|
exit_code_file.close()
|
||
|
_print_to_file_and_flush('Released lock of exit_code_file and closed it.',
|
||
|
file=stderr)
|
||
|
|
||
|
# Give tail a tiny bit of time to finish.
|
||
|
time.sleep(0.01)
|
||
|
|
||
|
_print_to_file_and_flush('Killing child processes.', file=stderr)
|
||
|
|
||
|
# clear the SIGCHLD handler so that killing the tails doesn't kill us
|
||
|
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
||
|
os.kill(stdout_pump.pid, signal.SIGTERM)
|
||
|
os.kill(stderr_pump.pid, signal.SIGTERM)
|
||
|
|
||
|
stderr.close()
|
||
|
# exit (with the same code as autotestd)
|
||
|
sys.exit(exit_code)
|