Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: tools/valgrind/common.py

Issue 7926011: Implement RunSubprocessChain to allow the tools call several processes connected by pipes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2009 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 os 6 import os
7 import signal 7 import signal
8 import subprocess 8 import subprocess
9 import sys 9 import sys
10 import time 10 import time
(...skipping 15 matching lines...) Expand all
26 if flush: 26 if flush:
27 sys.stdout.flush() 27 sys.stdout.flush()
28 28
29 29
30 def RunSubprocessInBackground(proc): 30 def RunSubprocessInBackground(proc):
31 """Runs a subprocess in the background. Returns a handle to the process.""" 31 """Runs a subprocess in the background. Returns a handle to the process."""
32 logging.info("running %s in the background" % " ".join(proc)) 32 logging.info("running %s in the background" % " ".join(proc))
33 return subprocess.Popen(proc) 33 return subprocess.Popen(proc)
34 34
35 35
36 def RunSubprocess(proc, timeout=0, detach=False, background=False): 36 def RunSubprocessChain(procs, timeout=0, detach=False, background=False):
37 """ Runs a subprocess, until it finishes or |timeout| is exceeded and the 37 """ Runs a chain of subprocesses, connected by a pipe until it finishes
38 process is killed with taskkill. A |timeout| <= 0 means no timeout. 38 or |timeout| is exceeded and the processes are killed with taskkill.
39 A |timeout| <= 0 means no timeout.
39 40
40 Args: 41 Args:
41 proc: list of process components (exe + args) 42 procs: list of commands to execute (each is a list of exe + args).
42 timeout: how long to wait before killing, <= 0 means wait forever 43 timeout: how long to wait before killing, <= 0 means wait forever
43 detach: Whether to pass the DETACHED_PROCESS argument to CreateProcess 44 detach: Whether to pass the DETACHED_PROCESS argument to CreateProcess
44 on Windows. This is used by Purify subprocesses on buildbot which 45 on Windows. This is used by Purify subprocesses on buildbot which
45 seem to get confused by the parent console that buildbot sets up. 46 seem to get confused by the parent console that buildbot sets up.
46 """ 47 """
47 48 command_str = " | ".join(map(lambda l: " ".join(l), procs))
48 logging.info("running %s, timeout %d sec" % (" ".join(proc), timeout)) 49 logging.info("running %s, timeout %d sec" % (command_str, timeout))
50 processes = []
49 if detach: 51 if detach:
52 if len(procs) > 1:
53 raise NotImplementedError("Chaining of detachable processes "
54 "is not supported yet.")
50 # see MSDN docs for "Process Creation Flags" 55 # see MSDN docs for "Process Creation Flags"
51 DETACHED_PROCESS = 0x8 56 DETACHED_PROCESS = 0x8
52 p = subprocess.Popen(proc, creationflags=DETACHED_PROCESS) 57 processes.append(subprocess.Popen(procs[0],
58 creationflags=DETACHED_PROCESS))
53 else: 59 else:
54 # For non-detached processes, manually read and print out stdout and stderr. 60 # For non-detached processes, manually read and print out stdout and stderr.
55 # By default, the subprocess is supposed to inherit these from its parent, 61 # By default, the subprocess is supposed to inherit these from its parent,
56 # however when run under buildbot, it seems unable to read data from a 62 # however when run under buildbot, it seems unable to read data from a
57 # grandchild process, so we have to read the child and print the data as if 63 # grandchild process, so we have to read the child and print the data as if
58 # it came from us for buildbot to read it. We're not sure why this is 64 # it came from us for buildbot to read it. We're not sure why this is
59 # necessary. 65 # necessary.
60 # TODO(erikkay): should we buffer stderr and stdout separately? 66 # TODO(erikkay): should we buffer stderr and stdout separately?
61 p = subprocess.Popen(proc, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 67 if len(procs) == 1:
62 68 processes.append(subprocess.Popen(procs[0],
69 stdout=subprocess.PIPE,
70 stderr=subprocess.STDOUT))
71 else:
72 first = True
73 for proc in procs:
74 if first:
75 processes.append(subprocess.Popen(proc,
76 stdout=subprocess.PIPE,
77 stderr=subprocess.STDOUT))
78 first = False
79 else:
80 processes.append(subprocess.Popen(proc,
81 stdin=processes[-1].stdout,
82 stdout=subprocess.PIPE,
83 stderr=subprocess.STDOUT))
63 logging.info("started subprocess") 84 logging.info("started subprocess")
64 85
65 # How long to wait (in seconds) before printing progress log messages. 86 # How long to wait (in seconds) before printing progress log messages.
66 progress_delay = 300 87 progress_delay = 300
67 progress_delay_time = time.time() + progress_delay 88 progress_delay_time = time.time() + progress_delay
68 did_timeout = False 89 did_timeout = False
69 if timeout > 0: 90 if timeout > 0:
70 wait_until = time.time() + timeout 91 wait_until = time.time() + timeout
71 while p.poll() is None and not did_timeout: 92 while processes[-1].poll() is None and not did_timeout:
72 if not detach: 93 if not detach:
73 line = p.stdout.readline() 94 line = processes[-1].stdout.readline()
74 while line and not did_timeout: 95 while line and not did_timeout:
75 _print_line(line) 96 _print_line(line)
76 line = p.stdout.readline() 97 line = processes[-1].stdout.readline()
77 if timeout > 0: 98 if timeout > 0:
M-A Ruel 2011/09/16 14:57:48 You should seriously consider using subprocess2, i
78 did_timeout = time.time() > wait_until 99 did_timeout = time.time() > wait_until
79 else: 100 else:
80 # When we detach, blocking on reading stdout doesn't work, so we sleep 101 # When we detach, blocking on reading stdout doesn't work, so we sleep
81 # a short time and poll. 102 # a short time and poll.
82 time.sleep(0.5) 103 time.sleep(0.5)
83 if time.time() >= progress_delay_time: 104 if time.time() >= progress_delay_time:
84 # Force output on a periodic basis to avoid getting killed off by the 105 # Force output on a periodic basis to avoid getting killed off by the
85 # buildbot. 106 # buildbot.
86 # TODO(erikkay): I'd prefer a less obtrusive 'print ".",' with a flush 107 # TODO(erikkay): I'd prefer a less obtrusive 'print ".",' with a flush
87 # but because of how we're doing subprocesses, this doesn't appear to 108 # but because of how we're doing subprocesses, this doesn't appear to
88 # work reliably. 109 # work reliably.
89 logging.info("%s still running..." % os.path.basename(proc[0])) 110 logging.info("%s still running..." % os.path.basename(procs[-1][0]))
90 progress_delay_time = time.time() + progress_delay 111 progress_delay_time = time.time() + progress_delay
91 if timeout > 0: 112 if timeout > 0:
92 did_timeout = time.time() > wait_until 113 did_timeout = time.time() > wait_until
93 114
94 if did_timeout: 115 if did_timeout:
95 logging.info("process timed out") 116 logging.info("process timed out")
96 else: 117 else:
97 logging.info("process ended, did not time out") 118 logging.info("process ended, did not time out")
98 119
99 if did_timeout: 120 if did_timeout:
100 if IsWindows(): 121 for p, proc in zip(processes, procs):
101 subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)]) 122 if IsWindows():
102 else: 123 subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)])
103 # Does this kill all children, too? 124 else:
104 os.kill(p.pid, signal.SIGINT) 125 # Does this kill all children, too?
105 logging.error("KILLED %d" % p.pid) 126 os.kill(p.pid, signal.SIGINT)
106 # Give the process a chance to actually die before continuing 127 logging.error("KILLED %d" % p.pid)
107 # so that cleanup can happen safely. 128 # Give the process a chance to actually die before continuing
108 time.sleep(1.0) 129 # so that cleanup can happen safely.
109 logging.error("TIMEOUT waiting for %s" % proc[0]) 130 time.sleep(1.0)
131 logging.error("TIMEOUT waiting for %s" % proc[0])
110 raise TimeoutError(proc[0]) 132 raise TimeoutError(proc[0])
111 elif not detach: 133 elif not detach:
112 for line in p.stdout.readlines(): 134 for line in processes[-1].stdout.readlines():
113 _print_line(line, False) 135 _print_line(line, False)
114 if not IsMac(): # stdout flush fails on Mac 136 if not IsMac(): # stdout flush fails on Mac
115 logging.info("flushing stdout") 137 logging.info("flushing stdout")
116 p.stdout.flush() 138 processes[-1].stdout.flush()
117 139
118 logging.info("collecting result code") 140 logging.info("collecting result code")
119 result = p.poll() 141 result = processes[-1].poll()
120 if result: 142 if result:
121 logging.error("%s exited with non-zero result code %d" % (proc[0], result)) 143 logging.error("%s exited with non-zero result code %d"
144 % (procs[0][0], result))
122 return result 145 return result
123 146
147 def RunSubprocess(proc, timeout=0, detach=False, background=False):
148 """ Runs a subprocess, until it finishes or |timeout| is exceeded and the
149 process is killed with taskkill. A |timeout| <= 0 means no timeout.
150
151 Args:
152 proc: list of process components (exe + args)
153 timeout: how long to wait before killing, <= 0 means wait forever
154 detach: Whether to pass the DETACHED_PROCESS argument to CreateProcess
155 on Windows. This is used by Purify subprocesses on buildbot which
156 seem to get confused by the parent console that buildbot sets up.
157 """
158 return RunSubprocessChain([proc], timeout, detach, background)
159
160
124 161
125 def IsLinux(): 162 def IsLinux():
126 return sys.platform.startswith('linux') 163 return sys.platform.startswith('linux')
127 164
128 165
129 def IsMac(): 166 def IsMac():
130 return sys.platform.startswith('darwin') 167 return sys.platform.startswith('darwin')
131 168
132 169
133 def IsWindows(): 170 def IsWindows():
134 return sys.platform == 'cygwin' or sys.platform.startswith('win') 171 return sys.platform == 'cygwin' or sys.platform.startswith('win')
135 172
136 173
137 def PlatformNames(): 174 def PlatformNames():
138 """Return an array of string to be used in paths for the platform 175 """Return an array of string to be used in paths for the platform
139 (e.g. suppressions, gtest filters, ignore files etc.) 176 (e.g. suppressions, gtest filters, ignore files etc.)
140 The first element of the array describes the 'main' platform 177 The first element of the array describes the 'main' platform
141 """ 178 """
142 if IsLinux(): 179 if IsLinux():
143 return ['linux'] 180 return ['linux']
144 if IsMac(): 181 if IsMac():
145 return ['mac'] 182 return ['mac']
146 if IsWindows(): 183 if IsWindows():
147 return ['win32'] 184 return ['win32']
148 raise NotImplementedError('Unknown platform "%s".' % sys.platform) 185 raise NotImplementedError('Unknown platform "%s".' % sys.platform)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698