@@ -92,145 +92,150 @@ def __init__(self, msg, errno=-1):
9292if sys .platform == "win32" and sys .getwindowsversion ()[3 ] == 2 :
9393
9494 import winprocess
95- from subprocess import pywintypes , list2cmdline , STARTUPINFO
9695 try :
97- # These subprocess variables have moved around between Python versions.
98- from subprocess import (SW_HIDE ,
99- STARTF_USESTDHANDLES , STARTF_USESHOWWINDOW ,
100- GetVersion , CreateProcess , TerminateProcess )
96+ from subprocess import pywintypes , list2cmdline , STARTUPINFO
10197 except ImportError :
102- import subprocess
103- SW_HIDE = subprocess ._subprocess .SW_HIDE
104- STARTF_USESTDHANDLES = subprocess ._subprocess .STARTF_USESTDHANDLES
105- STARTF_USESHOWWINDOW = subprocess ._subprocess .STARTF_USESHOWWINDOW
106- GetVersion = subprocess ._subprocess .GetVersion
107- CreateProcess = subprocess ._subprocess .CreateProcess
108- TerminateProcess = subprocess ._subprocess .TerminateProcess
109-
110- # This fix is for killing child processes on windows, based on:
111- # http://www.microsoft.com/msj/0698/win320698.aspx
112- # It works by creating a uniquely named job object that will contain our
113- # process(es), starts the process in a suspended state, maps the process
114- # to a specific job object, resumes the process, from now on every child
115- # it will create will be assigned to the same job object. We can then
116- # later terminate this job object (and all of it's child processes).
117- #
118- # This code is based upon Benjamin Smedberg's killableprocess, see:
119- # http://benjamin.smedbergs.us/blog/2006-12-11/killableprocesspy/
120-
121- class WindowsKillablePopen (Popen ):
122-
123- _job = None
124-
125- def _execute_child (self , args , executable , preexec_fn , close_fds ,
126- cwd , env , universal_newlines ,
127- startupinfo , creationflags , shell ,
128- p2cread , p2cwrite ,
129- c2pread , c2pwrite ,
130- errread , errwrite ):
131- """Execute program (MS Windows version)"""
132-
133- if not isinstance (args , string_types ):
134- args = list2cmdline (args )
135-
136- # Process startup details
137- if startupinfo is None :
138- startupinfo = STARTUPINFO ()
139- if None not in (p2cread , c2pwrite , errwrite ):
140- startupinfo .dwFlags |= STARTF_USESTDHANDLES
141- startupinfo .hStdInput = p2cread
142- startupinfo .hStdOutput = c2pwrite
143- startupinfo .hStdError = errwrite
144-
145- if shell :
146- startupinfo .dwFlags |= STARTF_USESHOWWINDOW
147- startupinfo .wShowWindow = SW_HIDE
148- comspec = os .environ .get ("COMSPEC" , "cmd.exe" )
149- args = comspec + " /c " + args
150- if (GetVersion () >= 0x80000000 or
151- os .path .basename (comspec ).lower () == "command.com" ):
152- # Win9x, or using command.com on NT. We need to
153- # use the w9xpopen intermediate program. For more
154- # information, see KB Q150956
155- # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
156- w9xpopen = self ._find_w9xpopen ()
157- args = '"%s" %s' % (w9xpopen , args )
158- # Not passing CREATE_NEW_CONSOLE has been known to
159- # cause random failures on win9x. Specifically a
160- # dialog: "Your program accessed mem currently in
161- # use at xxx" and a hopeful warning about the
162- # stability of your system. Cost is Ctrl+C wont
163- # kill children.
164- creationflags |= CREATE_NEW_CONSOLE
165-
166- # We create a new job for this process, so that we can kill
167- # the process and any sub-processes
168- self ._job = winprocess .CreateJobObject ()
169- creationflags |= winprocess .CREATE_SUSPENDED
170- # Vista will launch Komodo in a job object itself, so we need
171- # to specify that the created process is not part of the Komodo
172- # job object, but instead specify that it will be using a
173- # separate breakaway job object, bug 83001.
174- creationflags |= winprocess .CREATE_BREAKAWAY_FROM_JOB
175-
176- # Start the process
177- try :
178- hp , ht , pid , tid = CreateProcess (executable , args ,
179- # no special security
180- None , None ,
181- int (not close_fds ),
182- creationflags ,
183- env ,
184- cwd ,
185- startupinfo )
186- except pywintypes .error as e :
187- # Translate pywintypes.error to WindowsError, which is
188- # a subclass of OSError. FIXME: We should really
189- # translate errno using _sys_errlist (or simliar), but
190- # how can this be done from Python?
191- raise WindowsError (* e .args )
192- except WindowsError :
193- log .error ("process.py: can't execute %r (%s)" , executable , args )
194- raise
195-
196- # Retain the process handle, but close the thread handle
197- self ._child_created = True
198- self ._handle = hp
199- self .pid = pid
200- if self ._job :
201- # Resume the thread.
202- winprocess .AssignProcessToJobObject (self ._job , int (hp ))
203- winprocess .ResumeThread (int (ht ))
204- ht .Close ()
205-
206- # Child is launched. Close the parent's copy of those pipe
207- # handles that only the child should have open. You need
208- # to make sure that no handles to the write end of the
209- # output pipe are maintained in this process or else the
210- # pipe will not close when the child process exits and the
211- # ReadFile will hang.
212- if p2cread is not None :
213- p2cread .Close ()
214- if c2pwrite is not None :
215- c2pwrite .Close ()
216- if errwrite is not None :
217- errwrite .Close ()
218-
219- def terminate (self ):
220- """Terminates the process"""
221- if self ._job :
222- winprocess .TerminateJobObject (self ._job , 127 )
223- self .returncode = 127
224- else :
225- # Cannot call the parent class, as there is no terminate method
226- # defined at the class level (it's added upon instantiation),
227- # so this is a copy of subprocess.Popen.terminate() code.
228- TerminateProcess (self ._handle , 1 )
98+ pass
99+ else :
100+ try :
101+ # These subprocess variables have moved around between Python versions.
102+ from subprocess import (SW_HIDE ,
103+ STARTF_USESTDHANDLES , STARTF_USESHOWWINDOW ,
104+ GetVersion , CreateProcess , TerminateProcess )
105+ except ImportError :
106+ import subprocess
107+ SW_HIDE = subprocess ._subprocess .SW_HIDE
108+ STARTF_USESTDHANDLES = subprocess ._subprocess .STARTF_USESTDHANDLES
109+ STARTF_USESHOWWINDOW = subprocess ._subprocess .STARTF_USESHOWWINDOW
110+ GetVersion = subprocess ._subprocess .GetVersion
111+ CreateProcess = subprocess ._subprocess .CreateProcess
112+ TerminateProcess = subprocess ._subprocess .TerminateProcess
113+
114+ # This fix is for killing child processes on windows, based on:
115+ # http://www.microsoft.com/msj/0698/win320698.aspx
116+ # It works by creating a uniquely named job object that will contain our
117+ # process(es), starts the process in a suspended state, maps the process
118+ # to a specific job object, resumes the process, from now on every child
119+ # it will create will be assigned to the same job object. We can then
120+ # later terminate this job object (and all of it's child processes).
121+ #
122+ # This code is based upon Benjamin Smedberg's killableprocess, see:
123+ # http://benjamin.smedbergs.us/blog/2006-12-11/killableprocesspy/
124+
125+ class WindowsKillablePopen (Popen ):
126+
127+ _job = None
128+
129+ def _execute_child (self , args , executable , preexec_fn , close_fds ,
130+ cwd , env , universal_newlines ,
131+ startupinfo , creationflags , shell ,
132+ p2cread , p2cwrite ,
133+ c2pread , c2pwrite ,
134+ errread , errwrite ):
135+ """Execute program (MS Windows version)"""
136+
137+ if not isinstance (args , string_types ):
138+ args = list2cmdline (args )
139+
140+ # Process startup details
141+ if startupinfo is None :
142+ startupinfo = STARTUPINFO ()
143+ if None not in (p2cread , c2pwrite , errwrite ):
144+ startupinfo .dwFlags |= STARTF_USESTDHANDLES
145+ startupinfo .hStdInput = p2cread
146+ startupinfo .hStdOutput = c2pwrite
147+ startupinfo .hStdError = errwrite
148+
149+ if shell :
150+ startupinfo .dwFlags |= STARTF_USESHOWWINDOW
151+ startupinfo .wShowWindow = SW_HIDE
152+ comspec = os .environ .get ("COMSPEC" , "cmd.exe" )
153+ args = comspec + " /c " + args
154+ if (GetVersion () >= 0x80000000 or
155+ os .path .basename (comspec ).lower () == "command.com" ):
156+ # Win9x, or using command.com on NT. We need to
157+ # use the w9xpopen intermediate program. For more
158+ # information, see KB Q150956
159+ # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
160+ w9xpopen = self ._find_w9xpopen ()
161+ args = '"%s" %s' % (w9xpopen , args )
162+ # Not passing CREATE_NEW_CONSOLE has been known to
163+ # cause random failures on win9x. Specifically a
164+ # dialog: "Your program accessed mem currently in
165+ # use at xxx" and a hopeful warning about the
166+ # stability of your system. Cost is Ctrl+C wont
167+ # kill children.
168+ creationflags |= CREATE_NEW_CONSOLE
169+
170+ # We create a new job for this process, so that we can kill
171+ # the process and any sub-processes
172+ self ._job = winprocess .CreateJobObject ()
173+ creationflags |= winprocess .CREATE_SUSPENDED
174+ # Vista will launch Komodo in a job object itself, so we need
175+ # to specify that the created process is not part of the Komodo
176+ # job object, but instead specify that it will be using a
177+ # separate breakaway job object, bug 83001.
178+ creationflags |= winprocess .CREATE_BREAKAWAY_FROM_JOB
179+
180+ # Start the process
181+ try :
182+ hp , ht , pid , tid = CreateProcess (executable , args ,
183+ # no special security
184+ None , None ,
185+ int (not close_fds ),
186+ creationflags ,
187+ env ,
188+ cwd ,
189+ startupinfo )
190+ except pywintypes .error as e :
191+ # Translate pywintypes.error to WindowsError, which is
192+ # a subclass of OSError. FIXME: We should really
193+ # translate errno using _sys_errlist (or simliar), but
194+ # how can this be done from Python?
195+ raise WindowsError (* e .args )
196+ except WindowsError :
197+ log .error ("process.py: can't execute %r (%s)" , executable , args )
198+ raise
199+
200+ # Retain the process handle, but close the thread handle
201+ self ._child_created = True
202+ self ._handle = hp
203+ self .pid = pid
204+ if self ._job :
205+ # Resume the thread.
206+ winprocess .AssignProcessToJobObject (self ._job , int (hp ))
207+ winprocess .ResumeThread (int (ht ))
208+ ht .Close ()
209+
210+ # Child is launched. Close the parent's copy of those pipe
211+ # handles that only the child should have open. You need
212+ # to make sure that no handles to the write end of the
213+ # output pipe are maintained in this process or else the
214+ # pipe will not close when the child process exits and the
215+ # ReadFile will hang.
216+ if p2cread is not None :
217+ p2cread .Close ()
218+ if c2pwrite is not None :
219+ c2pwrite .Close ()
220+ if errwrite is not None :
221+ errwrite .Close ()
222+
223+ def terminate (self ):
224+ """Terminates the process"""
225+ if self ._job :
226+ winprocess .TerminateJobObject (self ._job , 127 )
227+ self .returncode = 127
228+ else :
229+ # Cannot call the parent class, as there is no terminate method
230+ # defined at the class level (it's added upon instantiation),
231+ # so this is a copy of subprocess.Popen.terminate() code.
232+ TerminateProcess (self ._handle , 1 )
233+
234+ kill = terminate
229235
230- kill = terminate
236+ # Use our own killable process instead of the regular Popen.
237+ Popen = WindowsKillablePopen
231238
232- # Use our own killable process instead of the regular Popen.
233- Popen = WindowsKillablePopen
234239
235240class ProcessOpen (Popen ):
236241
0 commit comments