Chromium Code Reviews| 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 |