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

Side by Side Diff: pylib/mozrunner/killableprocess.py

Issue 6183003: Added third_party python libraries that are needed for browser testing. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/third_party/
Patch Set: Created 9 years, 11 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 | « pylib/mozrunner/__init__.py ('k') | pylib/mozrunner/qijo.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # killableprocess - subprocesses which can be reliably killed
2 #
3 # Parts of this module are copied from the subprocess.py file contained
4 # in the Python distribution.
5 #
6 # Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
7 #
8 # Additions and modifications written by Benjamin Smedberg
9 # <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
10 # <http://www.mozilla.org/>
11 #
12 # More Modifications
13 # Copyright (c) 2006-2007 by Mike Taylor <bear@code-bear.com>
14 # Copyright (c) 2007-2008 by Mikeal Rogers <mikeal@mozilla.com>
15 #
16 # By obtaining, using, and/or copying this software and/or its
17 # associated documentation, you agree that you have read, understood,
18 # and will comply with the following terms and conditions:
19 #
20 # Permission to use, copy, modify, and distribute this software and
21 # its associated documentation for any purpose and without fee is
22 # hereby granted, provided that the above copyright notice appears in
23 # all copies, and that both that copyright notice and this permission
24 # notice appear in supporting documentation, and that the name of the
25 # author not be used in advertising or publicity pertaining to
26 # distribution of the software without specific, written prior
27 # permission.
28 #
29 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
30 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
31 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
32 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
34 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
35 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
36
37 """killableprocess - Subprocesses which can be reliably killed
38
39 This module is a subclass of the builtin "subprocess" module. It allows
40 processes that launch subprocesses to be reliably killed on Windows (via the Pop en.kill() method.
41
42 It also adds a timeout argument to Wait() for a limited period of time before
43 forcefully killing the process.
44
45 Note: On Windows, this module requires Windows 2000 or higher (no support for
46 Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with
47 Python 2.5+ or available from http://python.net/crew/theller/ctypes/
48 """
49
50 import subprocess
51 import sys
52 import os
53 import time
54 import datetime
55 import types
56 import exceptions
57
58 try:
59 from subprocess import CalledProcessError
60 except ImportError:
61 # Python 2.4 doesn't implement CalledProcessError
62 class CalledProcessError(Exception):
63 """This exception is raised when a process run by check_call() returns
64 a non-zero exit status. The exit status will be stored in the
65 returncode attribute."""
66 def __init__(self, returncode, cmd):
67 self.returncode = returncode
68 self.cmd = cmd
69 def __str__(self):
70 return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
71
72 mswindows = (sys.platform == "win32")
73
74 if mswindows:
75 import winprocess
76 else:
77 import signal
78
79 def call(*args, **kwargs):
80 waitargs = {}
81 if "timeout" in kwargs:
82 waitargs["timeout"] = kwargs.pop("timeout")
83
84 return Popen(*args, **kwargs).wait(**waitargs)
85
86 def check_call(*args, **kwargs):
87 """Call a program with an optional timeout. If the program has a non-zero
88 exit status, raises a CalledProcessError."""
89
90 retcode = call(*args, **kwargs)
91 if retcode:
92 cmd = kwargs.get("args")
93 if cmd is None:
94 cmd = args[0]
95 raise CalledProcessError(retcode, cmd)
96
97 if not mswindows:
98 def DoNothing(*args):
99 pass
100
101 class Popen(subprocess.Popen):
102 kill_called = False
103 if mswindows:
104 def _execute_child(self, args, executable, preexec_fn, close_fds,
105 cwd, env, universal_newlines, startupinfo,
106 creationflags, shell,
107 p2cread, p2cwrite,
108 c2pread, c2pwrite,
109 errread, errwrite):
110 if not isinstance(args, types.StringTypes):
111 args = subprocess.list2cmdline(args)
112
113 # Always or in the create new process group
114 creationflags |= winprocess.CREATE_NEW_PROCESS_GROUP
115
116 if startupinfo is None:
117 startupinfo = winprocess.STARTUPINFO()
118
119 if None not in (p2cread, c2pwrite, errwrite):
120 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
121
122 startupinfo.hStdInput = int(p2cread)
123 startupinfo.hStdOutput = int(c2pwrite)
124 startupinfo.hStdError = int(errwrite)
125 if shell:
126 startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
127 startupinfo.wShowWindow = winprocess.SW_HIDE
128 comspec = os.environ.get("COMSPEC", "cmd.exe")
129 args = comspec + " /c " + args
130
131 # determine if we can create create a job
132 canCreateJob = winprocess.CanCreateJobObject()
133
134 # set process creation flags
135 creationflags |= winprocess.CREATE_SUSPENDED
136 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
137 if canCreateJob:
138 creationflags |= winprocess.CREATE_BREAKAWAY_FROM_JOB
139
140 # create the process
141 hp, ht, pid, tid = winprocess.CreateProcess(
142 executable, args,
143 None, None, # No special security
144 1, # Must inherit handles!
145 creationflags,
146 winprocess.EnvironmentBlock(env),
147 cwd, startupinfo)
148 self._child_created = True
149 self._handle = hp
150 self._thread = ht
151 self.pid = pid
152 self.tid = tid
153
154 if canCreateJob:
155 # We create a new job for this process, so that we can kill
156 # the process and any sub-processes
157 self._job = winprocess.CreateJobObject()
158 winprocess.AssignProcessToJobObject(self._job, int(hp))
159 else:
160 self._job = None
161
162 winprocess.ResumeThread(int(ht))
163 ht.Close()
164
165 if p2cread is not None:
166 p2cread.Close()
167 if c2pwrite is not None:
168 c2pwrite.Close()
169 if errwrite is not None:
170 errwrite.Close()
171 time.sleep(.1)
172
173 def kill(self, group=True):
174 """Kill the process. If group=True, all sub-processes will also be kille d."""
175 self.kill_called = True
176 if mswindows:
177 if group and self._job:
178 winprocess.TerminateJobObject(self._job, 127)
179 else:
180 try:
181 winprocess.TerminateProcess(self._handle, 127)
182 except:
183 # TODO: better error handling here
184 pass
185 self.returncode = 127
186 else:
187 if group:
188 try:
189 os.killpg(self.pid, signal.SIGKILL)
190 except: pass
191 else:
192 os.kill(self.pid, signal.SIGKILL)
193 self.returncode = -9
194
195 def wait(self, timeout=None, group=True):
196 """Wait for the process to terminate. Returns returncode attribute.
197 If timeout seconds are reached and the process has not terminated,
198 it will be forcefully killed. If timeout is -1, wait will not
199 time out."""
200
201 if timeout is not None:
202 # timeout is now in milliseconds
203 timeout = timeout * 1000
204
205 if self.returncode is not None:
206 return self.returncode
207
208 starttime = datetime.datetime.now()
209
210 if mswindows:
211 if timeout is None:
212 timeout = -1
213 rc = winprocess.WaitForSingleObject(self._handle, timeout)
214
215 if rc != winprocess.WAIT_TIMEOUT:
216 def check():
217 now = datetime.datetime.now()
218 diff = now - starttime
219 if (diff.seconds * 1000 * 1000 + diff.microseconds) < (timeo ut * 1000):
220 if self._job:
221 if (winprocess.QueryInformationJobObject(self._job, 8)['BasicInfo']['ActiveProcesses'] > 0):
222 return True
223 else:
224 return True
225 return False
226 while check():
227 time.sleep(.5)
228
229 now = datetime.datetime.now()
230 diff = now - starttime
231 if (diff.seconds * 1000 * 1000 + diff.microseconds) > (timeout * 100 0):
232 self.kill(group)
233 else:
234 self.returncode = winprocess.GetExitCodeProcess(self._handle)
235 else:
236 if (sys.platform == 'linux2') or (sys.platform in ('sunos5', 'solari s')):
237 def group_wait(timeout):
238 try:
239 os.waitpid(self.pid, 0)
240 except OSError, e:
241 pass # If wait has already been called on this pid, bad things happen
242 return self.returncode
243 elif sys.platform == 'darwin':
244 def group_wait(timeout):
245 try:
246 count = 0
247 if timeout is None and self.kill_called:
248 timeout = 10 # Have to set some kind of timeout or e lse this could go on forever
249 if timeout is None:
250 while 1:
251 os.killpg(self.pid, signal.SIG_DFL)
252 while ((count * 2) <= timeout):
253 os.killpg(self.pid, signal.SIG_DFL)
254 # count is increased by 500ms for every 0.5s of slee p
255 time.sleep(.5); count += 500
256 except exceptions.OSError:
257 return self.returncode
258
259 if timeout is None:
260 if group is True:
261 return group_wait(timeout)
262 else:
263 subprocess.Popen.wait(self)
264 return self.returncode
265
266 returncode = False
267
268 now = datetime.datetime.now()
269 diff = now - starttime
270 while (diff.seconds * 1000 * 1000 + diff.microseconds) < (timeout * 1000) and ( returncode is False ):
271 if group is True:
272 return group_wait(timeout)
273 else:
274 if subprocess.poll() is not None:
275 returncode = self.returncode
276 time.sleep(.5)
277 now = datetime.datetime.now()
278 diff = now - starttime
279 return self.returncode
280
281 return self.returncode
282 # We get random maxint errors from subprocesses __del__
283 __del__ = lambda self: None
284
285 def setpgid_preexec_fn():
286 os.setpgid(0, 0)
287
288 def runCommand(cmd, **kwargs):
289 if sys.platform != "win32":
290 return Popen(cmd, preexec_fn=setpgid_preexec_fn, **kwargs)
291 else:
292 return Popen(cmd, **kwargs)
OLDNEW
« no previous file with comments | « pylib/mozrunner/__init__.py ('k') | pylib/mozrunner/qijo.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698