OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging | 5 import logging |
6 import platform | 6 import platform |
7 import os | 7 import os |
8 import signal | 8 import signal |
9 import subprocess | 9 import subprocess |
10 import sys | 10 import sys |
11 import time | 11 import time |
12 | 12 |
13 | 13 |
14 class NotImplementedError(Exception): | 14 class NotImplementedError(Exception): |
15 pass | 15 pass |
16 | 16 |
17 | 17 |
18 class TimeoutError(Exception): | 18 class TimeoutError(Exception): |
19 pass | 19 pass |
20 | 20 |
21 | 21 |
22 def _print_line(line, flush=True): | |
23 # Printing to a text file (including stdout) on Windows always winds up | |
24 # using \r\n automatically. On buildbot, this winds up being read by a master | |
25 # running on Linux, so we manually convert crlf to '\n' | |
26 print line.rstrip() + '\n', | |
27 if flush: | |
28 sys.stdout.flush() | |
29 | |
30 | |
31 def RunSubprocessInBackground(proc): | 22 def RunSubprocessInBackground(proc): |
32 """Runs a subprocess in the background. Returns a handle to the process.""" | 23 """Runs a subprocess in the background. Returns a handle to the process.""" |
33 logging.info("running %s in the background" % " ".join(proc)) | 24 logging.info("running %s in the background" % " ".join(proc)) |
34 return subprocess.Popen(proc) | 25 return subprocess.Popen(proc) |
35 | 26 |
36 | 27 |
37 def RunSubprocess(proc, timeout=0, detach=False, background=False): | 28 def RunSubprocess(proc, timeout=0): |
Timur Iskhodzhanov
2013/05/27 13:51:30
FYI: these were never used
| |
38 """ Runs a subprocess, until it finishes or |timeout| is exceeded and the | 29 """ Runs a subprocess, until it finishes or |timeout| is exceeded and the |
39 process is killed with taskkill. A |timeout| <= 0 means no timeout. | 30 process is killed with taskkill. A |timeout| <= 0 means no timeout. |
40 | 31 |
41 Args: | 32 Args: |
42 proc: list of process components (exe + args) | 33 proc: list of process components (exe + args) |
43 timeout: how long to wait before killing, <= 0 means wait forever | 34 timeout: how long to wait before killing, <= 0 means wait forever |
44 detach: Whether to pass the DETACHED_PROCESS argument to CreateProcess | |
45 on Windows. This is used by Purify subprocesses on buildbot which | |
46 seem to get confused by the parent console that buildbot sets up. | |
47 """ | 35 """ |
48 | 36 |
49 logging.info("running %s, timeout %d sec" % (" ".join(proc), timeout)) | 37 logging.info("running %s, timeout %d sec" % (" ".join(proc), timeout)) |
50 if detach: | 38 # Manually read and print out stdout and stderr. |
51 # see MSDN docs for "Process Creation Flags" | 39 # By default, the subprocess is supposed to inherit these from its parent, |
52 DETACHED_PROCESS = 0x8 | 40 # however when run under buildbot, it seems unable to read data from a |
53 p = subprocess.Popen(proc, creationflags=DETACHED_PROCESS) | 41 # grandchild process, so we have to read the child and print the data as if |
54 else: | 42 # it came from us for buildbot to read it. We're not sure why this is |
55 # For non-detached processes, manually read and print out stdout and stderr. | 43 # necessary. |
56 # By default, the subprocess is supposed to inherit these from its parent, | 44 # TODO(erikkay): should we buffer stderr and stdout separately? |
57 # however when run under buildbot, it seems unable to read data from a | 45 p = subprocess.Popen(proc, universal_newlines=True, |
58 # grandchild process, so we have to read the child and print the data as if | 46 bufsize=1, # line buffered |
59 # it came from us for buildbot to read it. We're not sure why this is | 47 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
60 # necessary. | |
61 # TODO(erikkay): should we buffer stderr and stdout separately? | |
62 p = subprocess.Popen(proc, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | |
63 | 48 |
64 logging.info("started subprocess") | 49 logging.info("started subprocess") |
65 | 50 |
66 # How long to wait (in seconds) before printing progress log messages. | 51 # How long to wait (in seconds) before printing progress log messages. |
67 progress_delay = 300 | 52 progress_delay = 300 |
68 progress_delay_time = time.time() + progress_delay | 53 progress_delay_time = time.time() + progress_delay |
69 did_timeout = False | 54 did_timeout = False |
70 if timeout > 0: | 55 if timeout > 0: |
71 wait_until = time.time() + timeout | 56 wait_until = time.time() + timeout |
72 while p.poll() is None and not did_timeout: | 57 while p.poll() is None and not did_timeout: |
73 if not detach: | 58 for line in p.stdout: |
74 line = p.stdout.readline() | 59 sys.stdout.write(line) |
75 while line and not did_timeout: | 60 sys.stdout.flush() |
76 _print_line(line) | 61 if timeout > 0: |
77 line = p.stdout.readline() | 62 did_timeout = time.time() > wait_until |
78 if timeout > 0: | 63 if did_timeout: |
79 did_timeout = time.time() > wait_until | 64 break |
80 else: | |
81 # When we detach, blocking on reading stdout doesn't work, so we sleep | |
82 # a short time and poll. | |
83 time.sleep(0.5) | |
84 if time.time() >= progress_delay_time: | |
85 # Force output on a periodic basis to avoid getting killed off by the | |
86 # buildbot. | |
87 # TODO(erikkay): I'd prefer a less obtrusive 'print ".",' with a flush | |
88 # but because of how we're doing subprocesses, this doesn't appear to | |
89 # work reliably. | |
90 logging.info("%s still running..." % os.path.basename(proc[0])) | |
91 progress_delay_time = time.time() + progress_delay | |
92 if timeout > 0: | |
93 did_timeout = time.time() > wait_until | |
94 | 65 |
95 if did_timeout: | 66 if did_timeout: |
96 logging.info("process timed out") | 67 logging.info("process timed out") |
97 else: | 68 else: |
98 logging.info("process ended, did not time out") | 69 logging.info("process ended, did not time out") |
99 | 70 |
100 if did_timeout: | 71 if did_timeout: |
101 if IsWindows(): | 72 if IsWindows(): |
102 subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)]) | 73 subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)]) |
103 else: | 74 else: |
104 # Does this kill all children, too? | 75 # Does this kill all children, too? |
105 os.kill(p.pid, signal.SIGINT) | 76 os.kill(p.pid, signal.SIGINT) |
106 logging.error("KILLED %d" % p.pid) | 77 logging.error("KILLED %d" % p.pid) |
107 # Give the process a chance to actually die before continuing | 78 # Give the process a chance to actually die before continuing |
108 # so that cleanup can happen safely. | 79 # so that cleanup can happen safely. |
109 time.sleep(1.0) | 80 time.sleep(1.0) |
110 logging.error("TIMEOUT waiting for %s" % proc[0]) | 81 logging.error("TIMEOUT waiting for %s" % proc[0]) |
111 raise TimeoutError(proc[0]) | 82 raise TimeoutError(proc[0]) |
112 elif not detach: | 83 else: |
113 for line in p.stdout.readlines(): | 84 for line in p.stdout: |
114 _print_line(line, False) | 85 sys.stdout.write(line) |
115 if not IsMac(): # stdout flush fails on Mac | 86 if not IsMac(): # stdout flush fails on Mac |
116 logging.info("flushing stdout") | 87 logging.info("flushing stdout") |
117 p.stdout.flush() | 88 p.stdout.flush() |
118 | 89 |
119 logging.info("collecting result code") | 90 logging.info("collecting result code") |
120 result = p.poll() | 91 result = p.poll() |
121 if result: | 92 if result: |
122 logging.error("%s exited with non-zero result code %d" % (proc[0], result)) | 93 logging.error("%s exited with non-zero result code %d" % (proc[0], result)) |
123 return result | 94 return result |
124 | 95 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
270 return False | 241 return False |
271 | 242 |
272 print "-----------------------------------------------------" | 243 print "-----------------------------------------------------" |
273 print "Suppressions used:" | 244 print "Suppressions used:" |
274 print " count name" | 245 print " count name" |
275 for (name, count) in sorted(suppcounts.items(), key=lambda (k,v): (v,k)): | 246 for (name, count) in sorted(suppcounts.items(), key=lambda (k,v): (v,k)): |
276 print "%7d %s" % (count, name) | 247 print "%7d %s" % (count, name) |
277 print "-----------------------------------------------------" | 248 print "-----------------------------------------------------" |
278 sys.stdout.flush() | 249 sys.stdout.flush() |
279 return True | 250 return True |
OLD | NEW |