##// END OF EJS Templates
Fix vista bug: subprocess execution not working if not started from...
gvaroquaux -
Show More
@@ -1,177 +1,179 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 # Killable process does not work under vista when starting for
77 # something else than cmd.
76 78 skip = True
77 79 else:
78 80 import winprocess
79 81 else:
80 82 import signal
81 83
82 84 if not mswindows:
83 85 def DoNothing(*args):
84 86 pass
85 87
86 88
87 89 if skip:
88 90 Popen = subprocess.Popen
89 91 else:
90 92 class Popen(subprocess.Popen):
91 93 if not mswindows:
92 94 # Override __init__ to set a preexec_fn
93 95 def __init__(self, *args, **kwargs):
94 96 if len(args) >= 7:
95 97 raise Exception("Arguments preexec_fn and after must be passed by keyword.")
96 98
97 99 real_preexec_fn = kwargs.pop("preexec_fn", None)
98 100 def setpgid_preexec_fn():
99 101 os.setpgid(0, 0)
100 102 if real_preexec_fn:
101 103 apply(real_preexec_fn)
102 104
103 105 kwargs['preexec_fn'] = setpgid_preexec_fn
104 106
105 107 subprocess.Popen.__init__(self, *args, **kwargs)
106 108
107 109 if mswindows:
108 110 def _execute_child(self, args, executable, preexec_fn, close_fds,
109 111 cwd, env, universal_newlines, startupinfo,
110 112 creationflags, shell,
111 113 p2cread, p2cwrite,
112 114 c2pread, c2pwrite,
113 115 errread, errwrite):
114 116 if not isinstance(args, types.StringTypes):
115 117 args = subprocess.list2cmdline(args)
116 118
117 119 if startupinfo is None:
118 120 startupinfo = winprocess.STARTUPINFO()
119 121
120 122 if None not in (p2cread, c2pwrite, errwrite):
121 123 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
122 124
123 125 startupinfo.hStdInput = int(p2cread)
124 126 startupinfo.hStdOutput = int(c2pwrite)
125 127 startupinfo.hStdError = int(errwrite)
126 128 if shell:
127 129 startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
128 130 startupinfo.wShowWindow = winprocess.SW_HIDE
129 131 comspec = os.environ.get("COMSPEC", "cmd.exe")
130 132 args = comspec + " /c " + args
131 133
132 134 # We create a new job for this process, so that we can kill
133 135 # the process and any sub-processes
134 136 self._job = winprocess.CreateJobObject()
135 137
136 138 creationflags |= winprocess.CREATE_SUSPENDED
137 139 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
138 140
139 141 hp, ht, pid, tid = winprocess.CreateProcess(
140 142 executable, args,
141 143 None, None, # No special security
142 144 1, # Must inherit handles!
143 145 creationflags,
144 146 winprocess.EnvironmentBlock(env),
145 147 cwd, startupinfo)
146 148
147 149 self._child_created = True
148 150 self._handle = hp
149 151 self._thread = ht
150 152 self.pid = pid
151 153
152 154 winprocess.AssignProcessToJobObject(self._job, hp)
153 155 winprocess.ResumeThread(ht)
154 156
155 157 if p2cread is not None:
156 158 p2cread.Close()
157 159 if c2pwrite is not None:
158 160 c2pwrite.Close()
159 161 if errwrite is not None:
160 162 errwrite.Close()
161 163
162 164 def kill(self, group=True):
163 165 """Kill the process. If group=True, all sub-processes will also be killed."""
164 166 if mswindows:
165 167 if group:
166 168 winprocess.TerminateJobObject(self._job, 127)
167 169 else:
168 170 winprocess.TerminateProcess(self._handle, 127)
169 171 self.returncode = 127
170 172 else:
171 173 if group:
172 174 os.killpg(self.pid, signal.SIGKILL)
173 175 else:
174 176 os.kill(self.pid, signal.SIGKILL)
175 177 self.returncode = -9
176 178
177 179
General Comments 0
You need to be logged in to leave comments. Login now