2 # Copyright (c) 2002-2003 ActiveState
3 # See LICENSE.txt for license details.
4 """ Contents of LICENSE.txt:
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 Python interface for process control.
28 This module defines three Process classes for spawning,
29 communicating and control processes. They are: Process, ProcessOpen,
30 ProcessProxy. All of the classes allow one to specify the command (cmd),
31 starting working directory (cwd), and environment to create for the
32 new process (env) and to "wait" for termination of the child and
36 Use this class to simply launch a process (either a GUI app or a
37 console app in a new console) with which you do not intend to
38 communicate via it std handles.
41 Think of this as a super version of Python's os.popen3() method.
42 This spawns the given command and sets up pipes for
43 stdin/stdout/stderr which can then be used to communicate with
47 This is a heavy-weight class that, similar to ProcessOpen,
48 spawns the given commands and sets up pipes to the child's
49 stdin/stdout/stderr. However, it also starts three threads to
50 proxy communication between each of the child's and parent's std
51 handles. At the parent end of this communication are, by
52 default, IOBuffer objects. You may specify your own objects here
53 (usually sub-classing from IOBuffer, which handles some
54 synchronization issues for you). The result is that it is
55 possible to have your own IOBuffer instance that gets, say, a
56 .write() "event" for every write that the child does on its
59 Understanding ProcessProxy is pretty complex. Some examples
60 below attempt to help show some uses. Here is a diagram of the
64 ,---->->->------' ^ `------>->->----,
66 IOBuffer IOBuffer IOBuffer
67 (p.stdout) (p.stderr) (p.stdin)
69 _OutFileProxy _OutFileProxy _InFileProxy
72 `----<-<-<------, | ,------<-<-<----'
77 p = process.<Process class>(cmd='echo hi', ...)
78 #... use the various methods and attributes
81 A simple 'hello world':
83 >>> p = process.ProcessOpen(['echo', 'hello'])
86 >>> p.wait() # .wait() returns the child's exit status
89 Redirecting the stdout handler:
91 >>> p = process.ProcessProxy(['echo', 'hello'], stdout=sys.stdout)
94 Using stdin (need to use ProcessProxy here because it defaults to
95 text-mode translation on Windows, ProcessOpen does not support
97 >>> p = process.ProcessProxy(['sort'])
98 >>> p.stdin.write('5\n')
99 >>> p.stdin.write('2\n')
100 >>> p.stdin.write('7\n')
105 Specifying environment variables:
106 >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}'])
109 >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}'],
110 ... env={'FOO':'bar'})
114 Killing a long running process (On Linux, to poll you must use
116 >>> p = ProcessOpen(['perl', '-e', 'while (1) {}'])
118 ... p.wait(os.WNOHANG) # poll to see if is process still running
119 ... except ProcessError, ex:
120 ... if ex.errno == ProcessProxy.WAIT_TIMEOUT:
121 ... print "process is still running"
123 process is still running
128 Providing objects for stdin/stdout/stderr:
129 XXX write this, mention IOBuffer subclassing.
132 # - Discuss the decision to NOT have the stdout/stderr _OutFileProxy's
133 # wait for process termination before closing stdin. It will just
134 # close stdin when stdout is seen to have been closed. That is
135 # considered Good Enough (tm). Theoretically it would be nice to
136 # only abort the stdin proxying when the process terminates, but
137 # watching for process termination in any of the parent's thread
138 # adds the undesired condition that the parent cannot exit with the
139 # child still running. That sucks.
140 # XXX Note that I don't even know if the current stdout proxy even
141 # closes the stdin proxy at all.
142 # - DavidA: if I specify "unbuffered" for my stdin handler (in the
143 # ProcessProxy constructor) then the stdin IOBuffer should do a
144 # fparent.read() rather than a fparent.readline(). TrentM: can I do
145 # that? What happens?
153 if sys
.platform
.startswith("win"):
161 # constants pulled from win32con to save memory
162 VER_PLATFORM_WIN32_WINDOWS
= 1
166 DUPLICATE_SAME_ACCESS
= 2
174 class ProcessError(Exception):
175 def __init__(self
, msg
, errno
=-1):
176 Exception.__init
__(self
, msg
)
180 #---- internal logging facility
183 DEBUG
, INFO
, WARN
, ERROR
, FATAL
= range(5)
184 def __init__(self
, name
, level
=None, streamOrFileName
=sys
.stderr
):
187 self
.level
= self
.WARN
190 if type(streamOrFileName
) == types
.StringType
:
191 self
.stream
= open(streamOrFileName
, 'w')
192 self
._opennedStream
= 1
194 self
.stream
= streamOrFileName
195 self
._opennedStream
= 0
197 if self
._opennedStream
:
199 def _getLevelName(self
, level
):
207 return levelNameMap
[level
]
208 def log(self
, level
, msg
, *args
):
209 if level
< self
.level
:
211 message
= "%s: %s:" % (self
.name
, self
._getLevelName
(level
).lower())
212 message
= message
+ (msg
% args
) + "\n"
213 self
.stream
.write(message
)
215 def debug(self
, msg
, *args
):
216 self
.log(self
.DEBUG
, msg
, *args
)
217 def info(self
, msg
, *args
):
218 self
.log(self
.INFO
, msg
, *args
)
219 def warn(self
, msg
, *args
):
220 self
.log(self
.WARN
, msg
, *args
)
221 def error(self
, msg
, *args
):
222 self
.log(self
.ERROR
, msg
, *args
)
223 def fatal(self
, msg
, *args
):
224 self
.log(self
.FATAL
, msg
, *args
)
227 # - 'log' to log normal process handling
228 # - 'logres' to track system resource life
229 # - 'logfix' to track wait/kill proxying in _ThreadFixer
230 if 1: # normal/production usage
231 log
= Logger("process", Logger
.WARN
)
232 else: # development/debugging usage
233 log
= Logger("process", Logger
.DEBUG
, sys
.stdout
)
234 if 1: # normal/production usage
235 logres
= Logger("process.res", Logger
.WARN
)
236 else: # development/debugging usage
237 logres
= Logger("process.res", Logger
.DEBUG
, sys
.stdout
)
238 if 1: # normal/production usage
239 logfix
= Logger("process.waitfix", Logger
.WARN
)
240 else: # development/debugging usage
241 logfix
= Logger("process.waitfix", Logger
.DEBUG
, sys
.stdout
)
247 _version_
= (0, 5, 0)
249 # List of registered processes (see _(un)registerProcess).
254 #---- internal support routines
257 """Escape the given command line argument for the shell."""
258 #XXX There is a probably more that we should escape here.
259 return arg
.replace('"', r
'\"')
263 r
"""Join an arglist to a string appropriate for running.
266 >>> _joinArgv(['foo', 'bar "baz'])
271 if ' ' in arg
or ';' in arg
:
272 cmdstr
+= '"%s"' % _escapeArg(arg
)
274 cmdstr
+= _escapeArg(arg
)
276 if cmdstr
.endswith(' '): cmdstr
= cmdstr
[:-1] # strip trailing space
280 def _getPathFromEnv(env
):
281 """Return the PATH environment variable or None.
283 Do the right thing for case sensitivity per platform.
284 XXX Icky. This guarantee of proper case sensitivity of environment
285 variables should be done more fundamentally in this module.
287 if sys
.platform
.startswith("win"):
288 for key
in env
.keys():
289 if key
.upper() == "PATH":
294 if env
.has_key("PATH"):
300 def _whichFirstArg(cmd
, env
=None):
301 """Return the given command ensuring that the first arg (the command to
302 launch) is a full path to an existing file.
304 Raise a ProcessError if no such executable could be found.
306 # Parse out the first arg.
307 if cmd
.startswith('"'):
308 # The .replace() is to ensure it does not mistakenly find the
309 # second '"' in, say (escaped quote):
310 # "C:\foo\"bar" arg1 arg2
311 idx
= cmd
.replace('\\"', 'XX').find('"', 1)
313 raise ProcessError("Malformed command: %r" % cmd
)
314 first
, rest
= cmd
[1:idx
], cmd
[idx
+1:]
318 first
, rest
= cmd
.split(' ', 1)
320 first
, rest
= cmd
, ""
322 # Ensure the first arg is a valid path to the appropriate file.
325 altpath
= [os
.path
.dirname(first
)]
326 firstbase
= os
.path
.basename(first
)
327 candidates
= list(which
.which(firstbase
, path
=altpath
))
329 altpath
= _getPathFromEnv(env
)
331 candidates
= list(which
.which(first
, altpath
.split(os
.pathsep
)))
333 candidates
= list(which
.which(first
))
335 candidates
= list(which
.which(first
))
337 return _joinArgv( [candidates
[0]] ) + ' ' + rest
339 raise ProcessError("Could not find an appropriate leading command "\
343 if sys
.platform
.startswith("win"):
344 def _SaferCreateProcess(appName
, # app name
346 processSA
, # process security attributes
347 threadSA
, # thread security attributes
348 inheritHandles
, # are handles are inherited
349 creationFlags
, # creation flags
351 cwd
, # current working directory
352 si
): # STARTUPINFO pointer
353 """If CreateProcess fails from environment type inconsistency then
354 fix that and try again.
356 win32process.CreateProcess requires that all environment keys and
357 values either be all ASCII or all unicode. Try to remove this burden
358 from the user of process.py.
360 isWin9x
= win32api
.GetVersionEx()[3] == VER_PLATFORM_WIN32_WINDOWS
361 # On Win9x all keys and values of 'env' must be ASCII (XXX
362 # Actually this is probably only true if the Unicode support
363 # libraries, which are not installed by default, are not
364 # installed). On other Windows flavours all keys and values of
365 # 'env' must all be ASCII *or* all Unicode. We will try to
366 # automatically convert to the appropriate type, issuing a
367 # warning if such an automatic conversion is necessary.
369 #XXX Komodo 2.0 Beta 1 hack. This requirement should be
370 # pushed out to Komodo code using process.py. Or should it?
373 for key
, value
in env
.items():
374 aenv
[str(key
)] = str(value
)
378 _SaferCreateProcess(appName=%r,
383 """, appName
, cmd
, env
, cwd
, os
.getcwd())
385 hProcess
, hThread
, processId
, threadId\
386 = win32process
.CreateProcess(appName
, cmd
, processSA
,
387 threadSA
, inheritHandles
,
388 creationFlags
, env
, cwd
, si
)
389 except TypeError, ex
:
390 if ex
.args
== ('All dictionary items must be strings, or all must be unicode',):
391 # Try again with an all unicode environment.
392 #XXX Would be nice if didn't have to depend on the error
393 # string to catch this.
394 #XXX Removing this warning for 2.3 release. See bug
395 # 23215. The right fix is to correct the PHPAppInfo
396 # stuff to heed the warning.
398 #warnings.warn('env: ' + str(ex), stacklevel=4)
402 for key
, value
in env
.items():
403 aenv
[str(key
)] = str(value
)
404 except UnicodeError, ex
:
405 raise ProcessError(str(ex
))
409 for key
, val
in env
.items():
410 uenv
[unicode(key
)] = unicode(val
)
412 hProcess
, hThread
, processId
, threadId\
413 = win32process
.CreateProcess(appName
, cmd
, processSA
,
414 threadSA
, inheritHandles
,
415 creationFlags
, env
, cwd
,
419 return hProcess
, hThread
, processId
, threadId
422 # Maintain references to all spawned ProcessProxy objects to avoid hangs.
423 # Otherwise, if the user lets the a ProcessProxy object go out of
424 # scope before the process has terminated, it is possible to get a
425 # hang (at least it *used* to be so when we had the
426 # win32api.CloseHandle(<stdin handle>) call in the __del__() method).
427 # XXX Is this hang possible on Linux as well?
428 # A reference is removed from this list when the process's .wait or
429 # .kill method is called.
430 # XXX Should an atexit() handler be registered to kill all curently
431 # running processes? Else *could* get hangs, n'est ce pas?
432 def _registerProcess(process
):
434 log
.info("_registerprocess(process=%r)", process
)
436 # Clean up zombie processes.
437 # If the user does not call .wait() or .kill() on processes then
438 # the ProcessProxy object will not get cleaned up until Python
439 # exits and _processes goes out of scope. Under heavy usage that
440 # is a big memory waste. Cleaning up here alleviates that.
441 for p
in _processes
[:]: # use copy of _process, because we may modifiy it
443 # poll to see if is process still running
444 if sys
.platform
.startswith("win"):
449 _unregisterProcess(p
)
450 except ProcessError
, ex
:
451 if ex
.errno
== ProcessProxy
.WAIT_TIMEOUT
:
456 _processes
.append(process
)
458 def _unregisterProcess(process
):
460 log
.info("_unregisterProcess(process=%r)", process
)
462 _processes
.remove(process
)
468 def _fixupCommand(cmd
, env
=None):
469 """Fixup the command string so it is launchable via CreateProcess.
471 One cannot just launch, say "python", via CreateProcess. A full path
472 to an executable is required. In general there are two choices:
473 1. Launch the command string via the shell. The shell will find
474 the fullpath to the appropriate executable. This shell will
475 also be able to execute special shell commands, like "dir",
476 which don't map to an actual executable.
477 2. Find the fullpath to the appropriate executable manually and
480 Option (1) is preferred because you don't have to worry about not
481 exactly duplicating shell behaviour and you get the added bonus of
482 being able to launch "dir" and friends.
484 However, (1) is not always an option. Doing so when the shell is
485 command.com (as on all Win9x boxes) or when using WinNT's cmd.exe,
486 problems are created with .kill() because these shells seem to eat
487 up Ctrl-C's and Ctrl-Break's sent via
488 win32api.GenerateConsoleCtrlEvent(). Strangely this only happens
489 when spawn via this Python interface. For example, Ctrl-C get
490 through to hang.exe here:
491 C:\> ...\w9xpopen.exe "C:\WINDOWS\COMMAND.COM /c hang.exe"
494 >>> p = ProcessOpen('hang.exe')
495 # This results in the same command to CreateProcess as
499 Hence, for these platforms we fallback to option (2). Cons:
500 - cannot spawn shell commands like 'dir' directly
501 - cannot spawn batch files
503 if sys
.platform
.startswith("win"):
504 # Fixup the command string to spawn. (Lifted from
505 # posixmodule.c::_PyPopenCreateProcess() with some modifications)
506 comspec
= os
.environ
.get("COMSPEC", None)
507 win32Version
= win32api
.GetVersion()
509 raise ProcessError("Cannot locate a COMSPEC environment "\
510 "variable to use as the shell")
511 # Explicitly check if we are using COMMAND.COM. If we
512 # are then use the w9xpopen hack.
513 elif (win32Version
& 0x80000000L
== 0) and\
514 (win32Version
& 0x5L
>= 5) and\
515 os
.path
.basename(comspec
).lower() != "command.com":
516 # 2000/XP and not using command.com.
517 if '"' in cmd
or "'" in cmd
:
518 cmd
= comspec
+ ' /c "%s"' % cmd
520 cmd
= comspec
+ ' /c ' + cmd
521 elif (win32Version
& 0x80000000L
== 0) and\
522 (win32Version
& 0x5L
< 5) and\
523 os
.path
.basename(comspec
).lower() != "command.com":
524 # NT and not using command.com.
526 cmd
= _whichFirstArg(cmd
, env
)
528 raise ProcessError("Could not find a suitable executable "\
529 "to launch for '%s'. On WinNT you must manually prefix "\
530 "shell commands and batch files with 'cmd.exe /c' to "\
531 "have the shell run them." % cmd
)
533 # Oh gag, we're on Win9x and/or using COMMAND.COM. Use the
534 # workaround listed in KB: Q150956
535 w9xpopen
= os
.path
.join(
536 os
.path
.dirname(win32api
.GetModuleFileName(0)),
538 if not os
.path
.exists(w9xpopen
):
539 # Eeek - file-not-found - possibly an embedding
540 # situation - see if we can locate it in sys.exec_prefix
541 w9xpopen
= os
.path
.join(os
.path
.dirname(sys
.exec_prefix
),
543 if not os
.path
.exists(w9xpopen
):
545 "Can not locate 'w9xpopen.exe' which is needed "\
546 "for ProcessOpen to work with your shell or "\
548 ## This would be option (1):
549 #cmd = '%s "%s /c %s"'\
550 # % (w9xpopen, comspec, cmd.replace('"', '\\"'))
552 cmd
= _whichFirstArg(cmd
, env
)
554 raise ProcessError("Could not find a suitable executable "\
555 "to launch for '%s'. On Win9x you must manually prefix "\
556 "shell commands and batch files with 'command.com /c' "\
557 "to have the shell run them." % cmd
)
558 cmd
= '%s "%s"' % (w9xpopen
, cmd
.replace('"', '\\"'))
562 """Wrap a system file object, hiding some nitpicky details.
564 This class provides a Python file-like interface to either a Python
565 file object (pretty easy job), a file descriptor, or an OS-specific
566 file handle (e.g. Win32 handles to file objects on Windows). Any or
567 all of these object types may be passed to this wrapper. If more
568 than one is specified this wrapper prefers to work with certain one
570 - file descriptor (because usually this allows for
571 return-immediately-on-read-if-anything-available semantics and
572 also provides text mode translation on Windows)
573 - OS-specific handle (allows for the above read semantics)
574 - file object (buffering can cause difficulty for interacting
575 with spawned programs)
577 It also provides a place where related such objects can be kept
578 alive together to prevent premature ref-counted collection. (E.g. on
579 Windows a Python file object may be associated with a Win32 file
580 handle. If the file handle is not kept alive the Python file object
581 will cease to function.)
583 def __init__(self
, file=None, descriptor
=None, handle
=None):
585 self
._descriptor
= descriptor
586 self
._handle
= handle
588 if self
._descriptor
is not None or self
._handle
is not None:
589 self
._lineBuf
= "" # to support .readline()
594 def __getattr__(self
, name
):
595 """Forward to the underlying file object."""
596 if self
._file
is not None:
597 return getattr(self
._file
, name
)
599 raise ProcessError("no file object to pass '%s' attribute to"
602 def _win32Read(self
, nBytes
):
604 log
.info("[%s] _FileWrapper.read: waiting for read on pipe",
606 errCode
, text
= win32file
.ReadFile(self
._handle
, nBytes
)
607 except pywintypes
.error
, ex
:
608 # Ignore errors for now, like "The pipe is being closed.",
609 # etc. XXX There *may* be errors we don't want to avoid.
610 log
.info("[%s] _FileWrapper.read: error reading from pipe: %s",
613 assert errCode
== 0,\
614 "Why is 'errCode' from ReadFile non-zero? %r" % errCode
616 # Empty text signifies that the pipe has been closed on
618 log
.info("[%s] _FileWrapper.read: observed close of parent",
620 # Signal the child so it knows to stop listening.
624 log
.info("[%s] _FileWrapper.read: read %d bytes from pipe: %r",
625 id(self
), len(text
), text
)
628 def read(self
, nBytes
=-1):
629 # nBytes <= 0 means "read everything"
630 # Note that we are changing the "read everything" cue to
631 # include 0, because actually doing
632 # win32file.ReadFile(<handle>, 0) results in every subsequent
633 # read returning 0, i.e. it shuts down the pipe.
634 if self
._descriptor
is not None:
636 text
, self
._lineBuf
= self
._lineBuf
, ""
638 t
= os
.read(self
._descriptor
, 4092)
644 if len(self
._lineBuf
) >= nBytes
:
645 text
, self
._lineBuf
=\
646 self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:]
648 nBytesToGo
= nBytes
- len(self
._lineBuf
)
649 text
= self
._lineBuf
+ os
.read(self
._descriptor
,
653 elif self
._handle
is not None:
655 text
, self
._lineBuf
= self
._lineBuf
, ""
657 t
= self
._win
32Read
(4092)
663 if len(self
._lineBuf
) >= nBytes
:
664 text
, self
._lineBuf
=\
665 self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:]
667 nBytesToGo
= nBytes
- len(self
._lineBuf
)
668 text
, self
._lineBuf
=\
669 self
._lineBuf
+ self
._win
32Read
(nBytesToGo
), ""
671 elif self
._file
is not None:
672 return self
._file
.read(nBytes
)
674 raise "FileHandle.read: no handle to read with"
677 if self
._descriptor
is not None or self
._handle
is not None:
679 #XXX This is not portable to the Mac.
680 idx
= self
._lineBuf
.find('\n')
682 line
, self
._lineBuf
=\
683 self
._lineBuf
[:idx
+1], self
._lineBuf
[idx
+1:]
686 lengthBefore
= len(self
._lineBuf
)
688 if len(t
) <= lengthBefore
: # no new data was read
689 line
, self
._lineBuf
= self
._lineBuf
, ""
694 elif self
._file
is not None:
695 return self
._file
.readline()
697 raise "FileHandle.readline: no handle to read with"
700 if self
._descriptor
is not None or self
._handle
is not None:
703 line
= self
.readline()
709 elif self
._file
is not None:
710 return self
._file
.readlines()
712 raise "FileHandle.readline: no handle to read with"
714 def write(self
, text
):
715 if self
._descriptor
is not None:
716 os
.write(self
._descriptor
, text
)
717 elif self
._handle
is not None:
719 errCode
, nBytesWritten
= win32file
.WriteFile(self
._handle
, text
)
720 except pywintypes
.error
, ex
:
721 # Ingore errors like "The pipe is being closed.", for
723 log
.info("[%s] _FileWrapper.write: error writing to pipe, "\
726 assert errCode
== 0,\
727 "Why is 'errCode' from WriteFile non-zero? %r" % errCode
728 if not nBytesWritten
:
729 # No bytes written signifies that the pipe has been
730 # closed on the child's end.
731 log
.info("[%s] _FileWrapper.write: observed close of pipe",
735 log
.info("[%s] _FileWrapper.write: wrote %d bytes to pipe: %r",
736 id(self
), len(text
), text
)
737 elif self
._file
is not None:
738 self
._file
.write(text
)
740 raise "FileHandle.write: nothing to write with"
743 """Close all associated file objects and handles."""
744 log
.debug("[%s] _FileWrapper.close()", id(self
))
747 if self
._file
is not None:
748 log
.debug("[%s] _FileWrapper.close: close file", id(self
))
750 log
.debug("[%s] _FileWrapper.close: done file close", id(self
))
751 if self
._descriptor
is not None:
753 os
.close(self
._descriptor
)
756 # Ignore: OSError: [Errno 9] Bad file descriptor
757 # XXX *Should* we be ignoring this? It appears very
758 # *in*frequently in test_wait.py.
759 log
.debug("[%s] _FileWrapper.close: closing "\
760 "descriptor raised OSError", id(self
))
763 if self
._handle
is not None:
764 log
.debug("[%s] _FileWrapper.close: close handle", id(self
))
766 win32api
.CloseHandle(self
._handle
)
767 except win32api
.error
:
768 log
.debug("[%s] _FileWrapper.close: closing handle raised",
771 log
.debug("[%s] _FileWrapper.close: done closing handle",
775 return "<_FileWrapper: file:%r fd:%r os_handle:%r>"\
776 % (self
._file
, self
._descriptor
, self
._handle
)
779 class _CountingCloser
:
780 """Call .close() on the given object after own .close() is called
781 the precribed number of times.
783 def __init__(self
, objectsToClose
, count
):
785 "objectsToClose" is a list of object on which to call .close().
786 "count" is the number of times this object's .close() method
787 must be called before .close() is called on the given objects.
789 self
.objectsToClose
= objectsToClose
792 raise ProcessError("illegal 'count' value: %s" % self
.count
)
796 log
.debug("[%d] _CountingCloser.close(): count=%d", id(self
),
799 for objectToClose
in self
.objectsToClose
:
800 objectToClose
.close()
804 #---- public interface
809 One can optionally specify the starting working directory, the
810 process environment, and std handles to have the child process
811 inherit (all defaults are the parent's current settings). 'wait' and
812 'kill' method allow for control of the child's termination.
815 # - Rename this or merge it with ProcessOpen somehow.
817 if sys
.platform
.startswith("win"):
818 # .wait() argument constants
819 INFINITE
= win32event
.INFINITE
820 # .wait() return error codes
821 WAIT_FAILED
= win32event
.WAIT_FAILED
822 WAIT_TIMEOUT
= win32event
.WAIT_TIMEOUT
823 # creation "flags" constants
824 # XXX Should drop these and just document usage of
825 # win32process.CREATE_* constants on windows.
826 CREATE_NEW_CONSOLE
= win32process
.CREATE_NEW_CONSOLE
828 # .wait() argument constants
830 # .wait() return error codes
833 # creation "flags" constants
834 CREATE_NEW_CONSOLE
= 0x10 # same as win32process.CREATE_NEW_CONSOLE
836 def __init__(self
, cmd
, cwd
=None, env
=None, flags
=0):
837 """Create a child process.
839 "cmd" is a command string or argument vector to spawn.
840 "cwd" is a working directory in which to start the child process.
841 "env" is an environment dictionary for the child.
842 "flags" are system-specific process creation flags. On Windows
843 this can be a bitwise-OR of any of the win32process.CREATE_*
844 constants (Note: win32process.CREATE_NEW_PROCESS_GROUP is always
845 OR'd in). On Unix, this is currently ignored.
847 log
.info("Process.__init__(cmd=%r, cwd=%r, env=%r, flags=%r)",
848 cmd
, cwd
, env
, flags
)
851 raise ProcessError("You must specify a command.")
855 if sys
.platform
.startswith("win"):
856 self
._flags |
= win32process
.CREATE_NEW_PROCESS_GROUP
858 if sys
.platform
.startswith("win"):
859 self
._startOnWindows
()
861 self
.__retvalCache
= None
864 def _runChildOnUnix(self
):
865 #XXX Errors running the child do *not* get communicated back.
867 #XXX Perhaps we should *always* prefix with '/bin/sh -c'? There is a
868 # disparity btwn how this works on Linux and Windows.
869 if isinstance(self
._cmd
, types
.StringTypes
):
870 # This is easier than trying to reproduce shell interpretation to
871 # separate the arguments.
872 cmd
= ['/bin/sh', '-c', self
._cmd
]
876 # Close all file descriptors (except std*) inherited from the parent.
877 MAXFD
= 256 # Max number of file descriptors (os.getdtablesize()???)
878 for i
in range(3, MAXFD
):
886 os
.execvpe(cmd
[0], cmd
, self
._env
)
888 os
.execvp(cmd
[0], cmd
)
890 os
._exit
(1) # Should never get here.
892 def _forkAndExecChildOnUnix(self
):
893 """Fork and start the child process.
895 Sets self._pid as a side effect.
899 self
._runChildOnUnix
()
903 def _startOnUnix(self
):
909 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
910 self
._forkAndExecChildOnUnix
()
916 def _startOnWindows(self
):
917 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
918 # And arg vector was passed in.
919 cmd
= _joinArgv(self
._cmd
)
923 si
= win32process
.STARTUPINFO()
924 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
925 si
.wShowWindow
= SW_SHOWDEFAULT
927 if not (self
._flags
& self
.CREATE_NEW_CONSOLE
):
929 # We cannot then use _fixupCommand because this will cause a
930 # shell to be openned as the command is launched. Therefore need
931 # to ensure be have the full path to the executable to launch.
933 cmd
= _whichFirstArg(cmd
, self
._env
)
935 # Could not find the command, perhaps it is an internal
936 # shell command -- fallback to _fixupCommand
937 cmd
= _fixupCommand(cmd
, self
._env
)
939 cmd
= _fixupCommand(cmd
, self
._env
)
940 log
.debug("cmd = %r", cmd
)
942 # Start the child process.
944 self
._hProcess
, self
._hThread
, self
._processId
, self
._threadId\
945 = _SaferCreateProcess(
948 None, # process security attributes
949 None, # primary thread security attributes
950 0, # handles are inherited
951 self
._flags
, # creation flags
952 self
._env
, # environment
953 self
._cwd
, # current working directory
954 si
) # STARTUPINFO pointer
955 win32api
.CloseHandle(self
._hThread
)
956 except win32api
.error
, ex
:
957 raise ProcessError(msg
="Error creating process for '%s': %s"\
961 def wait(self
, timeout
=None):
962 """Wait for the started process to complete.
964 "timeout" (on Windows) is a floating point number of seconds after
965 which to timeout. Default is win32event.INFINITE.
966 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
967 (os.WNOHANG may be used to return immediately if the process has
968 not exited). Default is 0, i.e. wait forever.
970 If the wait time's out it will raise a ProcessError. Otherwise it
971 will return the child's exit value (on Windows) or the child's exit
972 status excoded as per os.waitpid() (on Linux):
973 "a 16-bit number, whose low byte is the signal number that killed
974 the process, and whose high byte is the exit status (if the
975 signal number is zero); the high bit of the low byte is set if a
976 core file was produced."
977 In the latter case, use the os.W*() methods to interpret the return
980 # XXX Or should returning the exit value be move out to another
981 # function as on Win32 process control? If so, then should
982 # perhaps not make WaitForSingleObject semantic transformation.
983 if sys
.platform
.startswith("win"):
985 timeout
= win32event
.INFINITE
987 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
989 rc
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
)
990 if rc
== win32event
.WAIT_FAILED
:
991 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
992 "terminate: %r" % self
._cmd
, rc
)
993 elif rc
== win32event
.WAIT_TIMEOUT
:
994 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
995 "terminate: %r" % self
._cmd
, rc
)
997 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
999 # os.waitpid() will raise:
1000 # OSError: [Errno 10] No child processes
1001 # on subsequent .wait() calls. Change these semantics to have
1002 # subsequent .wait() calls return the exit status and return
1003 # immediately without raising an exception.
1004 # (XXX It would require synchronization code to handle the case
1005 # of multiple simultaneous .wait() requests, however we can punt
1006 # on that because it is moot while Linux still has the problem
1007 # for which _ThreadFixer() exists.)
1008 if self
.__retvalCache
is not None:
1009 retval
= self
.__retvalCache
1013 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1014 if pid
== self
._pid
:
1015 self
.__retvalCache
= retval
= sts
1017 raise ProcessError("Wait for process timed out.",
1021 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1024 "exitCode" [deprecated, not supported] (Windows only) is the
1025 code the terminated process should exit with.
1026 "gracePeriod" (Windows only) is a number of seconds the process is
1027 allowed to shutdown with a WM_CLOSE signal before a hard
1028 terminate is called.
1029 "sig" (Unix only) is the signal to use to kill the process. Defaults
1030 to signal.SIGKILL. See os.kill() for more information.
1033 Try for an orderly shutdown via WM_CLOSE. If still running
1034 after gracePeriod (1 sec. default), terminate.
1036 if sys
.platform
.startswith("win"):
1038 # Send WM_CLOSE to windows in this process group.
1039 win32gui
.EnumWindows(self
._close
_, 0)
1041 # Send Ctrl-Break signal to all processes attached to this
1042 # console. This is supposed to trigger shutdown handlers in
1043 # each of the processes.
1045 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1047 except AttributeError:
1048 log
.warn("The win32api module does not have "\
1049 "GenerateConsoleCtrlEvent(). This may mean that "\
1050 "parts of this process group have NOT been killed.")
1051 except win32api
.error
, ex
:
1052 if ex
.args
[0] not in (6, 87):
1053 # Ignore the following:
1054 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1055 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1056 # Get error 6 if there is no console.
1059 # Last resort: call TerminateProcess if it has not yet.
1062 self
.wait(gracePeriod
)
1063 except ProcessError
, ex
:
1064 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1065 win32process
.TerminateProcess(self
._hProcess
, -1)
1066 win32api
.Sleep(100) # wait for resources to be released
1070 sig
= signal
.SIGKILL
1072 os
.kill(self
._pid
, sig
)
1075 # Ignore: OSError: [Errno 3] No such process
1078 def _close_(self
, hwnd
, dummy
):
1079 """Callback used by .kill() on Windows.
1081 EnumWindows callback - sends WM_CLOSE to any window owned by this
1084 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1085 if processId
== self
._processId
:
1087 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1090 class ProcessOpen(Process
):
1091 """Create a process and setup pipes to it standard handles.
1093 This is a super popen3.
1096 # - Share some implementation with Process and ProcessProxy.
1099 def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None):
1100 """Create a Process with proxy threads for each std handle.
1102 "cmd" is the command string or argument vector to run.
1103 "mode" (Windows only) specifies whether the pipes used to communicate
1104 with the child are openned in text, 't', or binary, 'b', mode.
1105 This is ignored on platforms other than Windows. Default is 't'.
1106 "cwd" optionally specifies the directory in which the child process
1107 should be started. Default is None, a.k.a. inherits the cwd from
1109 "env" is optionally a mapping specifying the environment in which to
1110 start the child. Default is None, a.k.a. inherits the environment
1113 # Keep a reference to ensure it is around for this object's destruction.
1115 log
.info("ProcessOpen.__init__(cmd=%r, mode=%r, cwd=%r, env=%r)",
1116 cmd
, mode
, cwd
, env
)
1119 raise ProcessError("You must specify a command.")
1123 if self
._mode
not in ('t', 'b'):
1124 raise ProcessError("'mode' must be 't' or 'b'.")
1127 if sys
.platform
.startswith("win"):
1128 self
._startOnWindows
()
1130 self
.__retvalCache
= None
1133 _registerProcess(self
)
1136 #XXX Should probably not rely upon this.
1137 logres
.info("[%s] ProcessOpen.__del__()", id(self
))
1139 del self
.__log
# drop reference
1142 if not self
._closed
:
1143 self
.__log
.info("[%s] ProcessOpen.close()" % id(self
))
1145 # Ensure that all IOBuffer's are closed. If they are not, these
1148 self
.__log
.info("[%s] ProcessOpen: closing stdin (%r)."\
1149 % (id(self
), self
.stdin
))
1151 except AttributeError:
1152 # May not have gotten far enough in the __init__ to set
1156 self
.__log
.info("[%s] ProcessOpen: closing stdout (%r)."\
1157 % (id(self
), self
.stdout
))
1159 except AttributeError:
1160 # May not have gotten far enough in the __init__ to set
1164 self
.__log
.info("[%s] ProcessOpen: closing stderr (%r)."\
1165 % (id(self
), self
.stderr
))
1167 except AttributeError:
1168 # May not have gotten far enough in the __init__ to set
1174 def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
,
1176 """Fork and start the child process.
1178 Sets self._pid as a side effect.
1181 if pid
== 0: # child
1182 os
.dup2(fdChildStdinRd
, 0)
1183 os
.dup2(fdChildStdoutWr
, 1)
1184 os
.dup2(fdChildStderrWr
, 2)
1185 self
._runChildOnUnix
()
1189 def _startOnUnix(self
):
1190 # Create pipes for std handles.
1191 fdChildStdinRd
, fdChildStdinWr
= os
.pipe()
1192 fdChildStdoutRd
, fdChildStdoutWr
= os
.pipe()
1193 fdChildStderrRd
, fdChildStderrWr
= os
.pipe()
1196 oldDir
= os
.getcwd()
1200 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
1201 self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
,
1206 os
.close(fdChildStdinRd
)
1207 os
.close(fdChildStdoutWr
)
1208 os
.close(fdChildStderrWr
)
1210 self
.stdin
= _FileWrapper(descriptor
=fdChildStdinWr
)
1211 logres
.info("[%s] ProcessOpen._start(): create child stdin: %r",
1212 id(self
), self
.stdin
)
1213 self
.stdout
= _FileWrapper(descriptor
=fdChildStdoutRd
)
1214 logres
.info("[%s] ProcessOpen._start(): create child stdout: %r",
1215 id(self
), self
.stdout
)
1216 self
.stderr
= _FileWrapper(descriptor
=fdChildStderrRd
)
1217 logres
.info("[%s] ProcessOpen._start(): create child stderr: %r",
1218 id(self
), self
.stderr
)
1220 def _startOnWindows(self
):
1221 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
1222 # An arg vector was passed in.
1223 cmd
= _joinArgv(self
._cmd
)
1227 # Create pipes for std handles.
1228 # (Set the bInheritHandle flag so pipe handles are inherited.)
1229 saAttr
= pywintypes
.SECURITY_ATTRIBUTES()
1230 saAttr
.bInheritHandle
= 1
1231 #XXX Should maybe try with os.pipe. Dunno what that does for
1232 # inheritability though.
1233 hChildStdinRd
, hChildStdinWr
= win32pipe
.CreatePipe(saAttr
, 0)
1234 hChildStdoutRd
, hChildStdoutWr
= win32pipe
.CreatePipe(saAttr
, 0)
1235 hChildStderrRd
, hChildStderrWr
= win32pipe
.CreatePipe(saAttr
, 0)
1238 # Duplicate the parent ends of the pipes so they are not
1240 hChildStdinWrDup
= win32api
.DuplicateHandle(
1241 win32api
.GetCurrentProcess(),
1243 win32api
.GetCurrentProcess(),
1246 DUPLICATE_SAME_ACCESS
)
1247 win32api
.CloseHandle(hChildStdinWr
)
1248 self
._hChildStdinWr
= hChildStdinWrDup
1249 hChildStdoutRdDup
= win32api
.DuplicateHandle(
1250 win32api
.GetCurrentProcess(),
1252 win32api
.GetCurrentProcess(),
1255 DUPLICATE_SAME_ACCESS
)
1256 win32api
.CloseHandle(hChildStdoutRd
)
1257 self
._hChildStdoutRd
= hChildStdoutRdDup
1258 hChildStderrRdDup
= win32api
.DuplicateHandle(
1259 win32api
.GetCurrentProcess(),
1261 win32api
.GetCurrentProcess(),
1264 DUPLICATE_SAME_ACCESS
)
1265 win32api
.CloseHandle(hChildStderrRd
)
1266 self
._hChildStderrRd
= hChildStderrRdDup
1268 # Set the translation mode and buffering.
1269 if self
._mode
== 't':
1273 fdChildStdinWr
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
)
1274 fdChildStdoutRd
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
)
1275 fdChildStderrRd
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
)
1277 self
.stdin
= _FileWrapper(descriptor
=fdChildStdinWr
,
1278 handle
=self
._hChildStdinWr
)
1279 logres
.info("[%s] ProcessOpen._start(): create child stdin: %r",
1280 id(self
), self
.stdin
)
1281 self
.stdout
= _FileWrapper(descriptor
=fdChildStdoutRd
,
1282 handle
=self
._hChildStdoutRd
)
1283 logres
.info("[%s] ProcessOpen._start(): create child stdout: %r",
1284 id(self
), self
.stdout
)
1285 self
.stderr
= _FileWrapper(descriptor
=fdChildStderrRd
,
1286 handle
=self
._hChildStderrRd
)
1287 logres
.info("[%s] ProcessOpen._start(): create child stderr: %r",
1288 id(self
), self
.stderr
)
1290 # Start the child process.
1291 si
= win32process
.STARTUPINFO()
1292 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
1293 si
.wShowWindow
= 0 # SW_HIDE
1294 si
.hStdInput
= hChildStdinRd
1295 si
.hStdOutput
= hChildStdoutWr
1296 si
.hStdError
= hChildStderrWr
1297 si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
1299 cmd
= _fixupCommand(cmd
, self
._env
)
1301 creationFlags
= win32process
.CREATE_NEW_PROCESS_GROUP
1303 self
._hProcess
, hThread
, self
._processId
, threadId\
1304 = _SaferCreateProcess(
1307 None, # process security attributes
1308 None, # primary thread security attributes
1309 1, # handles are inherited
1310 creationFlags
, # creation flags
1311 self
._env
, # environment
1312 self
._cwd
, # current working directory
1313 si
) # STARTUPINFO pointer
1314 except win32api
.error
, ex
:
1315 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0])
1316 win32api
.CloseHandle(hThread
)
1319 # Close child ends of pipes on the parent's side (the
1320 # parent's ends of the pipe are closed in the _FileWrappers.)
1321 win32file
.CloseHandle(hChildStdinRd
)
1322 win32file
.CloseHandle(hChildStdoutWr
)
1323 win32file
.CloseHandle(hChildStderrWr
)
1325 def wait(self
, timeout
=None):
1326 """Wait for the started process to complete.
1328 "timeout" (on Windows) is a floating point number of seconds after
1329 which to timeout. Default is win32event.INFINITE.
1330 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
1331 (os.WNOHANG may be used to return immediately if the process has
1332 not exited). Default is 0, i.e. wait forever.
1334 If the wait time's out it will raise a ProcessError. Otherwise it
1335 will return the child's exit value (on Windows) or the child's exit
1336 status excoded as per os.waitpid() (on Linux):
1337 "a 16-bit number, whose low byte is the signal number that killed
1338 the process, and whose high byte is the exit status (if the
1339 signal number is zero); the high bit of the low byte is set if a
1340 core file was produced."
1341 In the latter case, use the os.W*() methods to interpret the return
1344 # XXX Or should returning the exit value be move out to another
1345 # function as on Win32 process control? If so, then should
1346 # perhaps not make WaitForSingleObject semantic
1349 # - Need to rationalize the .wait() API for Windows vs. Unix.
1350 # It is a real pain in the current situation.
1351 if sys
.platform
.startswith("win"):
1353 timeout
= win32event
.INFINITE
1355 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
1357 #rc = win32event.WaitForSingleObject(self._hProcess, timeout)
1358 rc
= win32event
.WaitForSingleObject(self
._hProcess
, int(timeout
)) # MATT -- Making timeout an integer
1359 if rc
== win32event
.WAIT_FAILED
:
1360 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
1361 "terminate: %r" % self
._cmd
, rc
)
1362 elif rc
== win32event
.WAIT_TIMEOUT
:
1363 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
1364 "terminate: %r" % self
._cmd
, rc
)
1366 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
1368 # os.waitpid() will raise:
1369 # OSError: [Errno 10] No child processes
1370 # on subsequent .wait() calls. Change these semantics to have
1371 # subsequent .wait() calls return the exit status and return
1372 # immediately without raising an exception.
1373 # (XXX It would require synchronization code to handle the case
1374 # of multiple simultaneous .wait() requests, however we can punt
1375 # on that because it is moot while Linux still has the problem
1376 # for which _ThreadFixer() exists.)
1377 if self
.__retvalCache
is not None:
1378 retval
= self
.__retvalCache
1382 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1383 if pid
== self
._pid
:
1384 self
.__retvalCache
= retval
= sts
1386 raise ProcessError("Wait for process timed out.",
1388 _unregisterProcess(self
)
1391 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1394 "exitCode" [deprecated, not supported] (Windows only) is the
1395 code the terminated process should exit with.
1396 "gracePeriod" (Windows only) is a number of seconds the process is
1397 allowed to shutdown with a WM_CLOSE signal before a hard
1398 terminate is called.
1399 "sig" (Unix only) is the signal to use to kill the process. Defaults
1400 to signal.SIGKILL. See os.kill() for more information.
1403 Try for an orderly shutdown via WM_CLOSE. If still running
1404 after gracePeriod (1 sec. default), terminate.
1406 if sys
.platform
.startswith("win"):
1408 # Send WM_CLOSE to windows in this process group.
1409 win32gui
.EnumWindows(self
._close
_, 0)
1411 # Send Ctrl-Break signal to all processes attached to this
1412 # console. This is supposed to trigger shutdown handlers in
1413 # each of the processes.
1415 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1417 except AttributeError:
1418 log
.warn("The win32api module does not have "\
1419 "GenerateConsoleCtrlEvent(). This may mean that "\
1420 "parts of this process group have NOT been killed.")
1421 except win32api
.error
, ex
:
1422 if ex
.args
[0] not in (6, 87):
1423 # Ignore the following:
1424 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1425 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1426 # Get error 6 if there is no console.
1429 # Last resort: call TerminateProcess if it has not yet.
1432 self
.wait(gracePeriod
)
1433 except ProcessError
, ex
:
1434 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1435 win32process
.TerminateProcess(self
._hProcess
, -1)
1436 win32api
.Sleep(100) # wait for resources to be released
1440 sig
= signal
.SIGKILL
1442 os
.kill(self
._pid
, sig
)
1445 # Ignore: OSError: [Errno 3] No such process
1448 _unregisterProcess(self
)
1450 def _close_(self
, hwnd
, dummy
):
1451 """Callback used by .kill() on Windows.
1453 EnumWindows callback - sends WM_CLOSE to any window owned by this
1456 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1457 if processId
== self
._processId
:
1459 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1462 class ProcessProxy(Process
):
1463 """Create a process and proxy communication via the standard handles.
1465 #XXX To add to docstring:
1466 # - stdout/stderr proxy handling
1467 # - stdin proxy handling
1469 # - how to .start(), i.e. basic usage rules
1470 # - mention that pased in stdin/stdout/stderr objects have to
1471 # implement at least .write (is .write correct for stdin)?
1472 # - if you pass in stdin, stdout, and/or stderr streams it is the
1473 # user's responsibility to close them afterwards.
1474 # - 'cmd' arg can be a command string or an arg vector
1477 # - .suspend() and .resume()? See Win32::Process Perl module.
1479 def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None,
1480 stdin
=None, stdout
=None, stderr
=None):
1481 """Create a Process with proxy threads for each std handle.
1483 "cmd" is the command string or argument vector to run.
1484 "mode" (Windows only) specifies whether the pipes used to communicate
1485 with the child are openned in text, 't', or binary, 'b', mode.
1486 This is ignored on platforms other than Windows. Default is 't'.
1487 "cwd" optionally specifies the directory in which the child process
1488 should be started. Default is None, a.k.a. inherits the cwd from
1490 "env" is optionally a mapping specifying the environment in which to
1491 start the child. Default is None, a.k.a. inherits the environment
1493 "stdin", "stdout", "stderr" can be used to specify objects with
1494 file-like interfaces to handle read (stdout/stderr) and write
1495 (stdin) events from the child. By default a process.IOBuffer
1496 instance is assigned to each handler. IOBuffer may be
1497 sub-classed. See the IOBuffer doc string for more information.
1499 # Keep a reference to ensure it is around for this object's destruction.
1501 log
.info("ProcessProxy.__init__(cmd=%r, mode=%r, cwd=%r, env=%r, "\
1502 "stdin=%r, stdout=%r, stderr=%r)",
1503 cmd
, mode
, cwd
, env
, stdin
, stdout
, stderr
)
1506 raise ProcessError("You must specify a command.")
1508 if self
._mode
not in ('t', 'b'):
1509 raise ProcessError("'mode' must be 't' or 'b'.")
1513 self
.stdin
= IOBuffer(name
='<stdin>')
1517 self
.stdout
= IOBuffer(name
='<stdout>')
1519 self
.stdout
= stdout
1521 self
.stderr
= IOBuffer(name
='<stderr>')
1523 self
.stderr
= stderr
1526 if sys
.platform
.startswith("win"):
1527 self
._startOnWindows
()
1529 self
.__retvalCache
= None
1532 _registerProcess(self
)
1535 #XXX Should probably not rely upon this.
1536 logres
.info("[%s] ProcessProxy.__del__()", id(self
))
1538 del self
.__log
# drop reference
1541 if not self
._closed
:
1542 self
.__log
.info("[%s] ProcessProxy.close()" % id(self
))
1544 # Ensure that all IOBuffer's are closed. If they are not, these
1546 self
.__log
.info("[%s] ProcessProxy: closing stdin (%r)."\
1547 % (id(self
), self
.stdin
))
1550 self
._stdinProxy
.join()
1551 except AttributeError:
1552 # May not have gotten far enough in the __init__ to set
1555 self
.__log
.info("[%s] ProcessProxy: closing stdout (%r)."\
1556 % (id(self
), self
.stdout
))
1559 if self
._stdoutProxy
is not threading
.currentThread():
1560 self
._stdoutProxy
.join()
1561 except AttributeError:
1562 # May not have gotten far enough in the __init__ to set
1565 self
.__log
.info("[%s] ProcessProxy: closing stderr (%r)."\
1566 % (id(self
), self
.stderr
))
1569 if self
._stderrProxy
is not threading
.currentThread():
1570 self
._stderrProxy
.join()
1571 except AttributeError:
1572 # May not have gotten far enough in the __init__ to set
1578 def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
,
1580 """Fork and start the child process.
1582 Sets self._pid as a side effect.
1585 if pid
== 0: # child
1586 os
.dup2(fdChildStdinRd
, 0)
1587 os
.dup2(fdChildStdoutWr
, 1)
1588 os
.dup2(fdChildStderrWr
, 2)
1589 self
._runChildOnUnix
()
1593 def _startOnUnix(self
):
1594 # Create pipes for std handles.
1595 fdChildStdinRd
, fdChildStdinWr
= os
.pipe()
1596 fdChildStdoutRd
, fdChildStdoutWr
= os
.pipe()
1597 fdChildStderrRd
, fdChildStderrWr
= os
.pipe()
1600 oldDir
= os
.getcwd()
1604 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
1605 self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
,
1610 os
.close(fdChildStdinRd
)
1611 os
.close(fdChildStdoutWr
)
1612 os
.close(fdChildStderrWr
)
1614 childStdin
= _FileWrapper(descriptor
=fdChildStdinWr
)
1615 logres
.info("[%s] ProcessProxy._start(): create child stdin: %r",
1616 id(self
), childStdin
)
1617 childStdout
= _FileWrapper(descriptor
=fdChildStdoutRd
)
1618 logres
.info("[%s] ProcessProxy._start(): create child stdout: %r",
1619 id(self
), childStdout
)
1620 childStderr
= _FileWrapper(descriptor
=fdChildStderrRd
)
1621 logres
.info("[%s] ProcessProxy._start(): create child stderr: %r",
1622 id(self
), childStderr
)
1624 # Create proxy threads for the out pipes.
1625 self
._stdinProxy
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>')
1626 self
._stdinProxy
.start()
1627 # Clean up the parent's side of <stdin> when it is observed that
1628 # the child has closed its side of <stdout> and <stderr>. (This
1629 # is one way of determining when it is appropriate to clean up
1630 # this pipe, with compromises. See the discussion at the top of
1632 closer
= _CountingCloser([self
.stdin
, childStdin
, self
], 2)
1633 self
._stdoutProxy
= _OutFileProxy(childStdout
, self
.stdout
,
1636 self
._stdoutProxy
.start()
1637 self
._stderrProxy
= _OutFileProxy(childStderr
, self
.stderr
,
1640 self
._stderrProxy
.start()
1642 def _startOnWindows(self
):
1643 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
1644 # An arg vector was passed in.
1645 cmd
= _joinArgv(self
._cmd
)
1649 # Create pipes for std handles.
1650 # (Set the bInheritHandle flag so pipe handles are inherited.)
1651 saAttr
= pywintypes
.SECURITY_ATTRIBUTES()
1652 saAttr
.bInheritHandle
= 1
1653 #XXX Should maybe try with os.pipe. Dunno what that does for
1654 # inheritability though.
1655 hChildStdinRd
, hChildStdinWr
= win32pipe
.CreatePipe(saAttr
, 0)
1656 hChildStdoutRd
, hChildStdoutWr
= win32pipe
.CreatePipe(saAttr
, 0)
1657 hChildStderrRd
, hChildStderrWr
= win32pipe
.CreatePipe(saAttr
, 0)
1660 # Duplicate the parent ends of the pipes so they are not
1662 hChildStdinWrDup
= win32api
.DuplicateHandle(
1663 win32api
.GetCurrentProcess(),
1665 win32api
.GetCurrentProcess(),
1668 DUPLICATE_SAME_ACCESS
)
1669 win32api
.CloseHandle(hChildStdinWr
)
1670 self
._hChildStdinWr
= hChildStdinWrDup
1671 hChildStdoutRdDup
= win32api
.DuplicateHandle(
1672 win32api
.GetCurrentProcess(),
1674 win32api
.GetCurrentProcess(),
1677 DUPLICATE_SAME_ACCESS
)
1678 win32api
.CloseHandle(hChildStdoutRd
)
1679 self
._hChildStdoutRd
= hChildStdoutRdDup
1680 hChildStderrRdDup
= win32api
.DuplicateHandle(
1681 win32api
.GetCurrentProcess(),
1683 win32api
.GetCurrentProcess(),
1686 DUPLICATE_SAME_ACCESS
)
1687 win32api
.CloseHandle(hChildStderrRd
)
1688 self
._hChildStderrRd
= hChildStderrRdDup
1690 # Set the translation mode.
1691 if self
._mode
== 't':
1697 fdChildStdinWr
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
)
1698 fdChildStdoutRd
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
)
1699 fdChildStderrRd
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
)
1701 childStdin
= _FileWrapper(descriptor
=fdChildStdinWr
,
1702 handle
=self
._hChildStdinWr
)
1703 logres
.info("[%s] ProcessProxy._start(): create child stdin: %r",
1704 id(self
), childStdin
)
1705 childStdout
= _FileWrapper(descriptor
=fdChildStdoutRd
,
1706 handle
=self
._hChildStdoutRd
)
1707 logres
.info("[%s] ProcessProxy._start(): create child stdout: %r",
1708 id(self
), childStdout
)
1709 childStderr
= _FileWrapper(descriptor
=fdChildStderrRd
,
1710 handle
=self
._hChildStderrRd
)
1711 logres
.info("[%s] ProcessProxy._start(): create child stderr: %r",
1712 id(self
), childStderr
)
1714 # Start the child process.
1715 si
= win32process
.STARTUPINFO()
1716 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
1717 si
.wShowWindow
= 0 # SW_HIDE
1718 si
.hStdInput
= hChildStdinRd
1719 si
.hStdOutput
= hChildStdoutWr
1720 si
.hStdError
= hChildStderrWr
1721 si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
1723 cmd
= _fixupCommand(cmd
, self
._env
)
1724 log
.debug("cmd = %r", cmd
)
1726 creationFlags
= win32process
.CREATE_NEW_PROCESS_GROUP
1728 self
._hProcess
, hThread
, self
._processId
, threadId\
1729 = _SaferCreateProcess(
1732 None, # process security attributes
1733 None, # primary thread security attributes
1734 1, # handles are inherited
1735 creationFlags
, # creation flags
1736 self
._env
, # environment
1737 self
._cwd
, # current working directory
1738 si
) # STARTUPINFO pointer
1739 except win32api
.error
, ex
:
1740 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0])
1741 win32api
.CloseHandle(hThread
)
1744 # Close child ends of pipes on the parent's side (the
1745 # parent's ends of the pipe are closed in the _FileWrappers.)
1746 win32file
.CloseHandle(hChildStdinRd
)
1747 win32file
.CloseHandle(hChildStdoutWr
)
1748 win32file
.CloseHandle(hChildStderrWr
)
1750 # Create proxy threads for the pipes.
1751 self
._stdinProxy
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>')
1752 self
._stdinProxy
.start()
1753 # Clean up the parent's side of <stdin> when it is observed that
1754 # the child has closed its side of <stdout>. (This is one way of
1755 # determining when it is appropriate to clean up this pipe, with
1756 # compromises. See the discussion at the top of this module.)
1757 self
._stdoutProxy
= _OutFileProxy(childStdout
, self
.stdout
,
1758 [self
.stdin
, childStdin
, self
],
1760 self
._stdoutProxy
.start()
1761 self
._stderrProxy
= _OutFileProxy(childStderr
, self
.stderr
,
1763 self
._stderrProxy
.start()
1765 def wait(self
, timeout
=None):
1766 """Wait for the started process to complete.
1768 "timeout" (on Windows) is a floating point number of seconds after
1769 which to timeout. Default is win32event.INFINITE.
1770 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
1771 (os.WNOHANG may be used to return immediately if the process has
1772 not exited). Default is 0, i.e. wait forever.
1774 If the wait time's out it will raise a ProcessError. Otherwise it
1775 will return the child's exit value (on Windows) or the child's exit
1776 status excoded as per os.waitpid() (on Linux):
1777 "a 16-bit number, whose low byte is the signal number that killed
1778 the process, and whose high byte is the exit status (if the
1779 signal number is zero); the high bit of the low byte is set if a
1780 core file was produced."
1781 In the latter case, use the os.W*() methods to interpret the return
1784 # XXX Or should returning the exit value be move out to another
1785 # function as on Win32 process control? If so, then should
1786 # perhaps not make WaitForSingleObject semantic transformation.
1787 if sys
.platform
.startswith("win"):
1789 timeout
= win32event
.INFINITE
1791 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
1793 rc
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
)
1794 if rc
== win32event
.WAIT_FAILED
:
1795 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
1796 "terminate: %r" % self
._cmd
, rc
)
1797 elif rc
== win32event
.WAIT_TIMEOUT
:
1798 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
1799 "terminate: %r" % self
._cmd
, rc
)
1801 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
1803 # os.waitpid() will raise:
1804 # OSError: [Errno 10] No child processes
1805 # on subsequent .wait() calls. Change these semantics to have
1806 # subsequent .wait() calls return the exit status and return
1807 # immediately without raising an exception.
1808 # (XXX It would require synchronization code to handle the case
1809 # of multiple simultaneous .wait() requests, however we can punt
1810 # on that because it is moot while Linux still has the problem
1811 # for which _ThreadFixer() exists.)
1812 if self
.__retvalCache
is not None:
1813 retval
= self
.__retvalCache
1817 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1818 if pid
== self
._pid
:
1819 self
.__retvalCache
= retval
= sts
1821 raise ProcessError("Wait for process timed out.",
1823 _unregisterProcess(self
)
1826 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1829 "exitCode" [deprecated, not supported] (Windows only) is the
1830 code the terminated process should exit with.
1831 "gracePeriod" (Windows only) is a number of seconds the process is
1832 allowed to shutdown with a WM_CLOSE signal before a hard
1833 terminate is called.
1834 "sig" (Unix only) is the signal to use to kill the process. Defaults
1835 to signal.SIGKILL. See os.kill() for more information.
1838 Try for an orderly shutdown via WM_CLOSE. If still running
1839 after gracePeriod (1 sec. default), terminate.
1841 if sys
.platform
.startswith("win"):
1843 # Send WM_CLOSE to windows in this process group.
1844 win32gui
.EnumWindows(self
._close
_, 0)
1846 # Send Ctrl-Break signal to all processes attached to this
1847 # console. This is supposed to trigger shutdown handlers in
1848 # each of the processes.
1850 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1852 except AttributeError:
1853 log
.warn("The win32api module does not have "\
1854 "GenerateConsoleCtrlEvent(). This may mean that "\
1855 "parts of this process group have NOT been killed.")
1856 except win32api
.error
, ex
:
1857 if ex
.args
[0] not in (6, 87):
1858 # Ignore the following:
1859 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1860 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1861 # Get error 6 if there is no console.
1864 # Last resort: call TerminateProcess if it has not yet.
1867 self
.wait(gracePeriod
)
1868 except ProcessError
, ex
:
1869 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1870 win32process
.TerminateProcess(self
._hProcess
, -1)
1871 win32api
.Sleep(100) # wait for resources to be released
1875 sig
= signal
.SIGKILL
1877 os
.kill(self
._pid
, sig
)
1880 # Ignore: OSError: [Errno 3] No such process
1883 _unregisterProcess(self
)
1885 def _close_(self
, hwnd
, dummy
):
1886 """Callback used by .kill() on Windows.
1888 EnumWindows callback - sends WM_CLOSE to any window owned by this
1891 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1892 if processId
== self
._processId
:
1894 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1898 """Want to be able to both read and write to this buffer from
1899 difference threads and have the same read/write semantics as for a
1902 This class is subclass-able. _doRead(), _doWrite(), _doReadline(),
1903 _doClose(), _haveLine(), and _haveNumBytes() can be overridden for
1904 specific functionality. The synchronization issues (block on read
1905 until write provides the needed data, termination) are handled for
1909 .seek() # Because we are managing *two* positions (one each
1910 .tell() # for reading and writing), these do not make
1914 # - Is performance a problem? This will likely be slower that
1915 # StringIO.StringIO().
1917 def __init__(self
, mutex
=None, stateChange
=None, name
=None):
1918 """'name' can be set for debugging, it will be used in log messages."""
1919 if name
is not None:
1922 self
._name
= id(self
)
1923 log
.info("[%s] IOBuffer.__init__()" % self
._name
)
1926 # A state change is defined as the buffer being closed or a
1928 if mutex
is not None:
1931 self
._mutex
= threading
.Lock()
1932 if stateChange
is not None:
1933 self
._stateChange
= stateChange
1935 self
._stateChange
= threading
.Condition()
1938 def _doWrite(self
, s
):
1939 self
.__buf
+= s
# Append to buffer.
1942 log
.info("[%s] IOBuffer.write(s=%r)", self
._name
, s
)
1943 # Silently drop writes after the buffer has been close()'d.
1946 # If empty write, close buffer (mimicking behaviour from
1952 self
._mutex
.acquire()
1954 self
._stateChange
.acquire()
1955 self
._stateChange
.notifyAll() # Notify of the write().
1956 self
._stateChange
.release()
1957 self
._mutex
.release()
1959 def writelines(self
, list):
1960 self
.write(''.join(list))
1962 def _doRead(self
, n
):
1963 """Pop 'n' bytes from the internal buffer and return them."""
1965 idx
= len(self
.__buf
)
1967 idx
= min(n
, len(self
.__buf
))
1968 retval
, self
.__buf
= self
.__buf
[:idx
], self
.__buf
[idx
:]
1971 def read(self
, n
=-1):
1972 log
.info("[%s] IOBuffer.read(n=%r)" % (self
._name
, n
))
1973 log
.info("[%s] IOBuffer.read(): wait for data" % self
._name
)
1975 # Wait until the buffer is closed, i.e. no more writes will
1978 if self
._closed
: break
1979 #log.debug("[%s] <<< IOBuffer.read: state change .wait()"\
1981 self
._stateChange
.acquire()
1982 self
._stateChange
.wait()
1983 self
._stateChange
.release()
1984 #log.debug("[%s] >>> IOBuffer.read: done change .wait()"\
1987 # Wait until there are the requested number of bytes to read
1988 # (or until the buffer is closed, i.e. no more writes will
1990 # XXX WARNING: I *think* there is a race condition around
1991 # here whereby self.fparent.read() in _InFileProxy can
1992 # hang. *Sometime* test_stdin::test_stdin_buffer() will
1993 # hang. This was *before* I moved the
1994 # _stateChange.acquire() and .release() calls out side
1995 # of the 'while 1:' here. ...and now they are back
1998 if self
._closed
: break
1999 if self
._haveNumBytes
(n
): break
2000 #log.debug("[%s] <<< IOBuffer.read: state change .wait()"\
2002 self
._stateChange
.acquire()
2003 self
._stateChange
.wait()
2004 self
._stateChange
.release()
2005 #log.debug("[%s] >>> IOBuffer.read: done change .wait()"\
2007 log
.info("[%s] IOBuffer.read(): done waiting for data" % self
._name
)
2009 self
._mutex
.acquire()
2010 retval
= self
._doRead
(n
)
2011 self
._mutex
.release()
2014 def _doReadline(self
, n
):
2015 """Pop the front line (or n bytes of it, whichever is less) from
2016 the internal buffer and return it.
2018 idx
= self
.__buf
.find('\n')
2020 idx
= len(self
.__buf
)
2022 idx
+= 1 # include the '\n'
2025 retval
, self
.__buf
= self
.__buf
[:idx
], self
.__buf
[idx
:]
2028 def _haveLine(self
):
2029 return self
.__buf
.find('\n') != -1
2031 def _haveNumBytes(self
, n
=None):
2032 return len(self
.__buf
) >= n
2034 def readline(self
, n
=None):
2035 # Wait until there is a full line (or at least 'n' bytes)
2036 # in the buffer or until the buffer is closed, i.e. no more
2038 log
.info("[%s] IOBuffer.readline(n=%r)" % (self
._name
, n
))
2040 log
.info("[%s] IOBuffer.readline(): wait for data" % self
._name
)
2042 if self
._closed
: break
2043 if self
._haveLine
(): break
2044 if n
is not None and self
._haveNumBytes
(n
): break
2045 self
._stateChange
.acquire()
2046 self
._stateChange
.wait()
2047 self
._stateChange
.release()
2048 log
.info("[%s] IOBuffer.readline(): done waiting for data"\
2051 self
._mutex
.acquire()
2052 retval
= self
._doReadline
(n
)
2053 self
._mutex
.release()
2056 def readlines(self
):
2059 line
= self
.readline()
2070 if not self
._closed
:
2071 log
.info("[%s] IOBuffer.close()" % self
._name
)
2074 self
._stateChange
.acquire()
2075 self
._stateChange
.notifyAll() # Notify of the close().
2076 self
._stateChange
.release()
2079 log
.info("[%s] IOBuffer.flush()" % self
._name
)
2080 #XXX Perhaps flush() should unwedged possible waiting .read()
2081 # and .readline() calls that are waiting for more data???
2084 class _InFileProxy(threading
.Thread
):
2085 """A thread to proxy stdin.write()'s from the parent to the child."""
2086 def __init__(self
, fParent
, fChild
, name
=None):
2088 "fParent" is a Python file-like object setup for writing.
2089 "fChild" is a Win32 handle to the a child process' output pipe.
2090 "name" can be set for debugging, it will be used in log messages.
2092 log
.info("[%s, %s] _InFileProxy.__init__(fChild=%r, fParent=%r)",
2093 name
, id(self
), fChild
, fParent
)
2094 threading
.Thread
.__init
__(self
, name
=name
)
2095 self
.fChild
= fChild
2096 self
.fParent
= fParent
2099 log
.info("[%s] _InFileProxy: start" % self
.getName())
2101 self
._proxyFromParentToChild
()
2103 log
.info("[%s] _InFileProxy: closing parent (%r)"\
2104 % (self
.getName(), self
.fParent
))
2106 self
.fParent
.close()
2108 pass # Ignore: IOError: [Errno 4] Interrupted system call
2109 log
.info("[%s] _InFileProxy: done" % self
.getName())
2111 def _proxyFromParentToChild(self
):
2113 # Read output from the child process, and (for now) just write
2116 log
.info("[%s] _InFileProxy: waiting for read on parent (%r)"\
2117 % (self
.getName(), self
.fParent
))
2118 # XXX Get hangs here (!) even with
2119 # self.stdin.close() in ProcessProxy' __del__() under this
2121 # p = ProcessProxy([...], stdin=sys.stdin)
2122 # The user must manually send '\n' via <Enter> or EOF
2123 # via <Ctrl-Z> to unlock this. How to get around that?
2124 # See cleanOnTermination note in _OutFileProxy.run()
2126 #log.debug("XXX -> start read on %r" % self.fParent)
2128 text
= self
.fParent
.read(CHUNKSIZE
)
2129 except ValueError, ex
:
2130 # ValueError is raised with trying to write to a closed
2133 #log.debug("XXX <- done read on %r" % self.fParent)
2135 # Empty text signifies that the pipe has been closed on
2137 log
.info("[%s] _InFileProxy: observed close of parent (%r)"\
2138 % (self
.getName(), self
.fParent
))
2139 # Signal the child so it knows to stop listening.
2141 logres
.info("[%s] _InFileProxy: closing child after "\
2142 "observing parent's close: %r", self
.getName(),
2147 pass # Ignore: IOError: [Errno 4] Interrupted system call
2149 # Ignore: IOError: [Errno 9] Bad file descriptor
2150 # XXX Do we *know* we want to do that?
2154 log
.info("[%s] _InFileProxy: read %d bytes from parent: %r"\
2155 % (self
.getName(), len(text
), text
))
2157 log
.info("[%s, %s] _InFileProxy: writing %r to child (%r)",
2158 self
.getName(), id(self
), text
, self
.fChild
)
2160 self
.fChild
.write(text
)
2161 except (OSError, IOError), ex
:
2162 # Ignore errors for now. For example:
2163 # - Get this on Win9x when writing multiple lines to "dir":
2164 # OSError: [Errno 32] Broken pipe
2165 #XXX There *may* be errors we don't want to avoid.
2166 #XXX Should maybe just ignore EnvironmentError (base class).
2167 log
.info("[%s] _InFileProxy: error writing to child (%r), "\
2168 "closing: %s" % (self
.getName(), self
.fParent
, ex
))
2170 log
.info("[%s] _InFileProxy: wrote %d bytes to child: %r"\
2171 % (self
.getName(), len(text
), text
))
2174 class _OutFileProxy(threading
.Thread
):
2175 """A thread to watch an "out" file from the spawned child process
2176 and pass on write's to the parent.
2178 def __init__(self
, fChild
, fParent
, toClose
=[], name
=None):
2180 "fChild" is a Win32 handle to the a child process' output pipe.
2181 "fParent" is a Python file-like object setup for writing.
2182 "toClose" is a list of objects on which to call .close when this
2183 proxy is terminating.
2184 "name" can be set for debugging, it will be used in log messages.
2186 log
.info("[%s] _OutFileProxy.__init__(fChild=%r, fParent=%r, "\
2187 "toClose=%r)", name
, fChild
, fParent
, toClose
)
2188 threading
.Thread
.__init
__(self
, name
=name
)
2189 self
.fChild
= fChild
2190 self
.fParent
= fParent
2191 self
.toClose
= toClose
2194 log
.info("[%s] _OutFileProxy: start" % self
.getName())
2196 self
._proxyFromChildToParent
()
2198 logres
.info("[%s] _OutFileProxy: terminating, close child (%r)",
2199 self
.getName(), self
.fChild
)
2203 pass # Ignore: IOError: [Errno 4] Interrupted system call
2204 log
.info("[%s] _OutFileProxy: closing parent (%r)",
2205 self
.getName(), self
.fParent
)
2207 self
.fParent
.close()
2209 pass # Ignore: IOError: [Errno 4] Interrupted system call
2211 logres
.info("[%s] _OutFileProxy: closing %r after "\
2212 "closing parent", self
.getName(), self
.toClose
[0])
2214 self
.toClose
[0].close()
2216 pass # Ignore: IOError: [Errno 4] Interrupted system call
2218 log
.info("[%s] _OutFileProxy: done" % self
.getName())
2220 def _proxyFromChildToParent(self
):
2222 # Read output from the child process, and (for now) just write
2227 log
.info("[%s] _OutFileProxy: waiting for read on child (%r)"\
2228 % (self
.getName(), self
.fChild
))
2229 text
= self
.fChild
.read(CHUNKSIZE
)
2231 # Ignore: IOError: [Errno 9] Bad file descriptor
2232 # XXX Do we *know* we want to do that?
2233 log
.info("[%s] _OutFileProxy: error reading from child (%r), "\
2234 "shutting down: %s", self
.getName(), self
.fChild
, ex
)
2237 # Empty text signifies that the pipe has been closed on
2239 log
.info("[%s] _OutFileProxy: observed close of child (%r)"\
2240 % (self
.getName(), self
.fChild
))
2243 log
.info("[%s] _OutFileProxy: text(len=%d): %r",
2244 self
.getName(), len(text
), text
)
2245 self
.fParent
.write(text
)
2249 if sys
.platform
.startswith("linux"):
2251 """Mixin class for various classes in the Process hierarchy to
2252 work around the known LinuxThreads bug where one cannot .wait()
2253 on a created process from a subthread of the thread that created
2257 class ProcessXXX(_ThreadFixer, BrokenProcessXXX):
2258 _pclass = BrokenProcessXXX
2261 Because we must do all real os.wait() calls on the child
2262 process from the thread that spawned it, we use a proxy
2263 thread whose only responsibility is just that. The proxy
2264 thread just starts the child and then immediately wait's for
2265 the child to terminate. On termination is stores the exit
2266 status (for use by the main thread) and notifies any thread
2267 waiting for this termination (possibly the main thread). The
2268 overriden .wait() uses this stored exit status and the
2269 termination notification to simulate the .wait().
2271 def __init__(self
, *args
, **kwargs
):
2272 # Keep a reference to 'log' ensure it is around for this object's
2275 self
.__waiter
= None
2276 self
.__hasTerminated
= threading
.Condition()
2277 self
.__terminationResult
= None
2278 self
.__childStarted
= threading
.Condition()
2279 self
._pclass
.__init
__(self
, *args
, **kwargs
)
2281 def _forkAndExecChildOnUnix(self
, *args
, **kwargs
):
2282 """Fork and start the child process do it in a special subthread
2283 that will negotiate subsequent .wait()'s.
2285 Sets self._pid as a side effect.
2287 self
.__waiter
= threading
.Thread(
2288 target
=self
.__launchAndWait
, args
=args
, kwargs
=kwargs
)
2290 # Start subthread that will launch child and wait until it
2292 self
.__childStarted
.acquire()
2293 self
.__waiter
.start()
2294 self
.__childStarted
.wait()
2295 self
.__childStarted
.release()
2297 def __launchAndWait(self
, *args
, **kwargs
):
2298 """Launch the given command and wait for it to terminate.
2300 When the process has terminated then store its exit value
2303 logfix
.info("start child in thread %s",
2304 threading
.currentThread().getName())
2306 # Spawn the child process and notify the main thread of
2308 self
.__childStarted
.acquire()
2309 self
._pclass
._forkAndExecChildOnUnix
(self
, *args
, **kwargs
)
2310 self
.__childStarted
.notifyAll()
2311 self
.__childStarted
.release()
2313 # Wait on the thread and store appropriate results when
2316 waitResult
= self
._pclass
.wait(self
)
2317 except ProcessError
, ex
:
2319 self
.__hasTerminated
.acquire()
2320 self
.__terminationResult
= waitResult
2321 self
.__hasTerminated
.notifyAll()
2322 self
.__hasTerminated
.release()
2324 self
.__waiter
= None # drop ref that would keep instance alive
2326 def wait(self
, timeout
=None):
2327 # If the process __hasTerminated then return the exit
2328 # status. Otherwise simulate the wait as appropriate.
2330 # - This class is only used on linux so 'timeout' has the
2331 # Unix 'timeout' semantics.
2332 self
.__hasTerminated
.acquire()
2333 if self
.__terminationResult
is None:
2334 if timeout
== os
.WNOHANG
: # Poll.
2335 self
.__hasTerminated
.wait(0)
2336 else: # Block until process finishes.
2337 self
.__hasTerminated
.wait()
2338 terminationResult
= self
.__terminationResult
2339 self
.__hasTerminated
.release()
2341 if terminationResult
is None:
2342 # process has not finished yet
2343 raise ProcessError("Wait for process timed out.",
2345 elif isinstance(terminationResult
, Exception):
2346 # some error waiting for process termination
2347 raise terminationResult
2349 # the process terminated
2350 return terminationResult
2352 _ThreadBrokenProcess
= Process
2353 class Process(_ThreadFixer
, _ThreadBrokenProcess
):
2354 _pclass
= _ThreadBrokenProcess
2356 _ThreadBrokenProcessOpen
= ProcessOpen
2357 class ProcessOpen(_ThreadFixer
, _ThreadBrokenProcessOpen
):
2358 _pclass
= _ThreadBrokenProcessOpen
2360 _ThreadBrokenProcessProxy
= ProcessProxy
2361 class ProcessProxy(_ThreadFixer
, _ThreadBrokenProcessProxy
):
2362 _pclass
= _ThreadBrokenProcessProxy