##// END OF EJS Templates
Fiw bug related to Vista subprocess call error
laurent dufrechou -
Show More
@@ -1,179 +1,182 b''
1 1 # Addapted from killableprocess.py.
2 2 #______________________________________________________________________________
3 3 #
4 4 # killableprocess - subprocesses which can be reliably killed
5 5 #
6 6 # Parts of this module are copied from the subprocess.py file contained
7 7 # in the Python distribution.
8 8 #
9 9 # Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
10 10 #
11 11 # Additions and modifications written by Benjamin Smedberg
12 12 # <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
13 13 # <http://www.mozilla.org/>
14 14 #
15 15 # By obtaining, using, and/or copying this software and/or its
16 16 # associated documentation, you agree that you have read, understood,
17 17 # and will comply with the following terms and conditions:
18 18 #
19 19 # Permission to use, copy, modify, and distribute this software and
20 20 # its associated documentation for any purpose and without fee is
21 21 # hereby granted, provided that the above copyright notice appears in
22 22 # all copies, and that both that copyright notice and this permission
23 23 # notice appear in supporting documentation, and that the name of the
24 24 # author not be used in advertising or publicity pertaining to
25 25 # distribution of the software without specific, written prior
26 26 # permission.
27 27 #
28 28 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
29 29 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
30 30 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
31 31 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
32 32 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
33 33 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
34 34 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 35
36 36 r"""killableprocess - Subprocesses which can be reliably killed
37 37
38 38 This module is a subclass of the builtin "subprocess" module. It allows
39 39 processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method.
40 40
41 41 It also adds a timeout argument to Wait() for a limited period of time before
42 42 forcefully killing the process.
43 43
44 44 Note: On Windows, this module requires Windows 2000 or higher (no support for
45 45 Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with
46 46 Python 2.5+ or available from http://python.net/crew/theller/ctypes/
47 47 """
48 48
49 49 import subprocess
50 50 from subprocess import PIPE
51 51 import sys
52 52 import os
53 53 import types
54 54
55 55 try:
56 56 from subprocess import CalledProcessError
57 57 except ImportError:
58 58 # Python 2.4 doesn't implement CalledProcessError
59 59 class CalledProcessError(Exception):
60 60 """This exception is raised when a process run by check_call() returns
61 61 a non-zero exit status. The exit status will be stored in the
62 62 returncode attribute."""
63 63 def __init__(self, returncode, cmd):
64 64 self.returncode = returncode
65 65 self.cmd = cmd
66 66 def __str__(self):
67 67 return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
68 68
69 69 mswindows = (sys.platform == "win32")
70 70
71 71 skip = False
72 72
73 73 if mswindows:
74 74 import platform
75 75 if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
76 76 # Killable process does not work under vista when starting for
77 77 # something else than cmd.
78 78 skip = True
79 79 else:
80 80 import winprocess
81 81 else:
82 82 import signal
83 83
84 84 if not mswindows:
85 85 def DoNothing(*args):
86 86 pass
87 87
88 88
89 89 if skip:
90 90 Popen = subprocess.Popen
91 91 else:
92 92 class Popen(subprocess.Popen):
93 93 if not mswindows:
94 94 # Override __init__ to set a preexec_fn
95 95 def __init__(self, *args, **kwargs):
96 96 if len(args) >= 7:
97 97 raise Exception("Arguments preexec_fn and after must be passed by keyword.")
98 98
99 99 real_preexec_fn = kwargs.pop("preexec_fn", None)
100 100 def setpgid_preexec_fn():
101 101 os.setpgid(0, 0)
102 102 if real_preexec_fn:
103 103 apply(real_preexec_fn)
104 104
105 105 kwargs['preexec_fn'] = setpgid_preexec_fn
106 106
107 107 subprocess.Popen.__init__(self, *args, **kwargs)
108 108
109 109 if mswindows:
110 110 def _execute_child(self, args, executable, preexec_fn, close_fds,
111 111 cwd, env, universal_newlines, startupinfo,
112 112 creationflags, shell,
113 113 p2cread, p2cwrite,
114 114 c2pread, c2pwrite,
115 115 errread, errwrite):
116 116 if not isinstance(args, types.StringTypes):
117 117 args = subprocess.list2cmdline(args)
118 118
119 119 if startupinfo is None:
120 120 startupinfo = winprocess.STARTUPINFO()
121 121
122 122 if None not in (p2cread, c2pwrite, errwrite):
123 123 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
124 124
125 125 startupinfo.hStdInput = int(p2cread)
126 126 startupinfo.hStdOutput = int(c2pwrite)
127 127 startupinfo.hStdError = int(errwrite)
128 128 if shell:
129 129 startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
130 130 startupinfo.wShowWindow = winprocess.SW_HIDE
131 131 comspec = os.environ.get("COMSPEC", "cmd.exe")
132 132 args = comspec + " /c " + args
133 133
134 134 # We create a new job for this process, so that we can kill
135 135 # the process and any sub-processes
136 136 self._job = winprocess.CreateJobObject()
137 137
138 138 creationflags |= winprocess.CREATE_SUSPENDED
139 139 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
140 140
141 141 hp, ht, pid, tid = winprocess.CreateProcess(
142 142 executable, args,
143 143 None, None, # No special security
144 144 1, # Must inherit handles!
145 145 creationflags,
146 146 winprocess.EnvironmentBlock(env),
147 147 cwd, startupinfo)
148 148
149 149 self._child_created = True
150 150 self._handle = hp
151 151 self._thread = ht
152 152 self.pid = pid
153 153
154 winprocess.AssignProcessToJobObject(self._job, hp)
154 try:
155 winprocess.AssignProcessToJobObject(self._job, hp)
156 except WindowsError:
157 pass
155 158 winprocess.ResumeThread(ht)
156 159
157 160 if p2cread is not None:
158 161 p2cread.Close()
159 162 if c2pwrite is not None:
160 163 c2pwrite.Close()
161 164 if errwrite is not None:
162 165 errwrite.Close()
163 166
164 167 def kill(self, group=True):
165 168 """Kill the process. If group=True, all sub-processes will also be killed."""
166 169 if mswindows:
167 170 if group:
168 171 winprocess.TerminateJobObject(self._job, 127)
169 172 else:
170 173 winprocess.TerminateProcess(self._handle, 127)
171 174 self.returncode = 127
172 175 else:
173 176 if group:
174 177 os.killpg(self.pid, signal.SIGKILL)
175 178 else:
176 179 os.kill(self.pid, signal.SIGKILL)
177 180 self.returncode = -9
178 181
179 182
General Comments 0
You need to be logged in to leave comments. Login now