##// END OF EJS Templates
Try to catter for exception in corner cases with some version of windows...
gvaroquaux -
Show More
@@ -1,168 +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 import time
54 53 import types
55 54
56 55 try:
57 56 from subprocess import CalledProcessError
58 57 except ImportError:
59 58 # Python 2.4 doesn't implement CalledProcessError
60 59 class CalledProcessError(Exception):
61 60 """This exception is raised when a process run by check_call() returns
62 61 a non-zero exit status. The exit status will be stored in the
63 62 returncode attribute."""
64 63 def __init__(self, returncode, cmd):
65 64 self.returncode = returncode
66 65 self.cmd = cmd
67 66 def __str__(self):
68 67 return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
69 68
70 69 mswindows = (sys.platform == "win32")
71 70
71 skip = False
72
72 73 if mswindows:
73 import winprocess
74 # Some versions of windows, in some strange corner cases, give
75 # errror with the killableprocess.
76 if sys.version_info[:2] > (2, 4):
77 import platform
78 if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
79 skip = True
80 else:
81 import winprocess
82 else:
83 skip = True
74 84 else:
75 85 import signal
76 86
77 87 if not mswindows:
78 88 def DoNothing(*args):
79 89 pass
80 90
81 class Popen(subprocess.Popen):
91
92 if skip:
93 Popen = subprocess.Popen
94 else:
95 class Popen(subprocess.Popen):
82 96 if not mswindows:
83 97 # Override __init__ to set a preexec_fn
84 98 def __init__(self, *args, **kwargs):
85 99 if len(args) >= 7:
86 100 raise Exception("Arguments preexec_fn and after must be passed by keyword.")
87 101
88 102 real_preexec_fn = kwargs.pop("preexec_fn", None)
89 103 def setpgid_preexec_fn():
90 104 os.setpgid(0, 0)
91 105 if real_preexec_fn:
92 106 apply(real_preexec_fn)
93 107
94 108 kwargs['preexec_fn'] = setpgid_preexec_fn
95 109
96 110 subprocess.Popen.__init__(self, *args, **kwargs)
97 111
98 112 if mswindows:
99 113 def _execute_child(self, args, executable, preexec_fn, close_fds,
100 114 cwd, env, universal_newlines, startupinfo,
101 115 creationflags, shell,
102 116 p2cread, p2cwrite,
103 117 c2pread, c2pwrite,
104 118 errread, errwrite):
105 119 if not isinstance(args, types.StringTypes):
106 120 args = subprocess.list2cmdline(args)
107 121
108 122 if startupinfo is None:
109 123 startupinfo = winprocess.STARTUPINFO()
110 124
111 125 if None not in (p2cread, c2pwrite, errwrite):
112 126 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
113 127
114 128 startupinfo.hStdInput = int(p2cread)
115 129 startupinfo.hStdOutput = int(c2pwrite)
116 130 startupinfo.hStdError = int(errwrite)
117 131 if shell:
118 132 startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
119 133 startupinfo.wShowWindow = winprocess.SW_HIDE
120 134 comspec = os.environ.get("COMSPEC", "cmd.exe")
121 135 args = comspec + " /c " + args
122 136
123 137 # We create a new job for this process, so that we can kill
124 138 # the process and any sub-processes
125 139 self._job = winprocess.CreateJobObject()
126 140
127 141 creationflags |= winprocess.CREATE_SUSPENDED
128 142 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
129 143
130 144 hp, ht, pid, tid = winprocess.CreateProcess(
131 145 executable, args,
132 146 None, None, # No special security
133 147 1, # Must inherit handles!
134 148 creationflags,
135 149 winprocess.EnvironmentBlock(env),
136 150 cwd, startupinfo)
137 151
138 152 self._child_created = True
139 153 self._handle = hp
140 154 self._thread = ht
141 155 self.pid = pid
142 156
143 157 winprocess.AssignProcessToJobObject(self._job, hp)
144 158 winprocess.ResumeThread(ht)
145 159
146 160 if p2cread is not None:
147 161 p2cread.Close()
148 162 if c2pwrite is not None:
149 163 c2pwrite.Close()
150 164 if errwrite is not None:
151 165 errwrite.Close()
152 166
153 167 def kill(self, group=True):
154 168 """Kill the process. If group=True, all sub-processes will also be killed."""
155 169 if mswindows:
156 170 if group:
157 171 winprocess.TerminateJobObject(self._job, 127)
158 172 else:
159 173 winprocess.TerminateProcess(self._handle, 127)
160 174 self.returncode = 127
161 175 else:
162 176 if group:
163 177 os.killpg(self.pid, signal.SIGKILL)
164 178 else:
165 179 os.kill(self.pid, signal.SIGKILL)
166 180 self.returncode = -9
167 181
168 182
General Comments 0
You need to be logged in to leave comments. Login now