xref: /aosp_15_r20/external/autotest/client/bin/autotestd_monitor (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/python3
2*9c5db199SXin Li
3*9c5db199SXin Lifrom __future__ import absolute_import
4*9c5db199SXin Lifrom __future__ import division
5*9c5db199SXin Lifrom __future__ import print_function
6*9c5db199SXin Liimport common
7*9c5db199SXin Liimport sys, os, signal, time, subprocess, fcntl
8*9c5db199SXin Li
9*9c5db199SXin Li
10*9c5db199SXin Lidef _print_to_file_and_flush(msg, file):
11*9c5db199SXin Li    """Print to the provided file, and flush after printing."""
12*9c5db199SXin Li    print(msg, file=file)
13*9c5db199SXin Li    file.flush()
14*9c5db199SXin Li
15*9c5db199SXin Lilogdir = sys.argv[1]
16*9c5db199SXin Listdout_start = int(sys.argv[2])  # number of bytes we can skip on stdout
17*9c5db199SXin Listderr_start = int(sys.argv[3])  # nubmer of bytes we can skip on stderr
18*9c5db199SXin Li# TODO (crosbug.com/38224)- sbasi: Remove extra logging.
19*9c5db199SXin Listderr = open(os.path.join(logdir, 'stderr'), 'a', buffering=2)
20*9c5db199SXin Li
21*9c5db199SXin Li_print_to_file_and_flush('Entered autotestd_monitor.', file=stderr)
22*9c5db199SXin Li
23*9c5db199SXin Li# if any of our tail processes die, the monitor should die too
24*9c5db199SXin Lidef kill_self(signum, frame):
25*9c5db199SXin Li    os.kill(os.getpid(), signal.SIGTERM)
26*9c5db199SXin Lisignal.signal(signal.SIGCHLD, kill_self)
27*9c5db199SXin Li
28*9c5db199SXin Lidevnull = open(os.devnull, 'w')
29*9c5db199SXin Li
30*9c5db199SXin Li# launch some tail processes to pump the std* streams
31*9c5db199SXin Lidef launch_tail(filename, outstream, start):
32*9c5db199SXin Li    path = os.path.join(logdir, filename)
33*9c5db199SXin Li    argv = ['tail', '--retry', '--follow=name', '--bytes=+%d' % start, path]
34*9c5db199SXin Li    # stdout=sys.stdout fails on pre-2.5 python (bug in subprocess module)
35*9c5db199SXin Li    if outstream != subprocess.PIPE and outstream.fileno() == 1:
36*9c5db199SXin Li        return subprocess.Popen(argv, stderr=devnull)
37*9c5db199SXin Li    else:
38*9c5db199SXin Li        return subprocess.Popen(argv, stdout=outstream, stderr=devnull)
39*9c5db199SXin Listdout_pump = launch_tail('stdout', sys.stdout, stdout_start)
40*9c5db199SXin Listderr_pump = launch_tail('stderr', sys.stderr, stderr_start)
41*9c5db199SXin Li
42*9c5db199SXin Li_print_to_file_and_flush('Finished launching tail subprocesses.', file=stderr)
43*9c5db199SXin Li# wait for logdir/started to exist to be sure autotestd is started
44*9c5db199SXin Listart_time = time.time()
45*9c5db199SXin Listarted_file_path = os.path.join(logdir, 'started')
46*9c5db199SXin Liwhile not os.path.exists(started_file_path):
47*9c5db199SXin Li    time.sleep(1)
48*9c5db199SXin Li    if time.time() - start_time >= 30:
49*9c5db199SXin Li        raise Exception("autotestd failed to start in %s" % logdir)
50*9c5db199SXin Li
51*9c5db199SXin Li_print_to_file_and_flush('Finished waiting on autotestd to start.',
52*9c5db199SXin Li                         file=stderr)
53*9c5db199SXin Li
54*9c5db199SXin Li# watch the exit code file for an exit
55*9c5db199SXin Liexit_code_file = open(os.path.join(logdir, 'exit_code'))
56*9c5db199SXin Lifcntl.flock(exit_code_file, fcntl.LOCK_EX)
57*9c5db199SXin Li_print_to_file_and_flush('Got lock of exit_code_file.', file=stderr)
58*9c5db199SXin Li
59*9c5db199SXin Litry:
60*9c5db199SXin Li    exit_code = exit_code_file.read()
61*9c5db199SXin Li    if len(exit_code) != 4:
62*9c5db199SXin Li        exit_code = -signal.SIGKILL   # autotestd was nuked
63*9c5db199SXin Li    else:
64*9c5db199SXin Li        exit_code = int(exit_code)
65*9c5db199SXin Lifinally:
66*9c5db199SXin Li    fcntl.flock(exit_code_file, fcntl.LOCK_UN)
67*9c5db199SXin Li    exit_code_file.close()
68*9c5db199SXin Li    _print_to_file_and_flush('Released lock of exit_code_file and closed it.',
69*9c5db199SXin Li                              file=stderr)
70*9c5db199SXin Li
71*9c5db199SXin Li# Give tail a tiny bit of time to finish.
72*9c5db199SXin Litime.sleep(0.01)
73*9c5db199SXin Li
74*9c5db199SXin Li_print_to_file_and_flush('Killing child processes.', file=stderr)
75*9c5db199SXin Li
76*9c5db199SXin Li# clear the SIGCHLD handler so that killing the tails doesn't kill us
77*9c5db199SXin Lisignal.signal(signal.SIGCHLD, signal.SIG_DFL)
78*9c5db199SXin Lios.kill(stdout_pump.pid, signal.SIGTERM)
79*9c5db199SXin Lios.kill(stderr_pump.pid, signal.SIGTERM)
80*9c5db199SXin Li
81*9c5db199SXin Listderr.close()
82*9c5db199SXin Li# exit (with the same code as autotestd)
83*9c5db199SXin Lisys.exit(exit_code)
84