84 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/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)
 |