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():
411 uenv
[unicode(key
)] = unicode(val
) # default encoding
414 uenv
[unicode(key
, 'iso-8859-1')] = unicode(val
, 'iso-8859-1') # backup encoding
416 log
.warn('Skipping environment variable "%s" in execution process: unable to convert to unicode using either the default encoding or ISO-8859-1' % (key
))
418 hProcess
, hThread
, processId
, threadId\
419 = win32process
.CreateProcess(appName
, cmd
, processSA
,
420 threadSA
, inheritHandles
,
421 creationFlags
, env
, cwd
,
425 return hProcess
, hThread
, processId
, threadId
428 # Maintain references to all spawned ProcessProxy objects to avoid hangs.
429 # Otherwise, if the user lets the a ProcessProxy object go out of
430 # scope before the process has terminated, it is possible to get a
431 # hang (at least it *used* to be so when we had the
432 # win32api.CloseHandle(<stdin handle>) call in the __del__() method).
433 # XXX Is this hang possible on Linux as well?
434 # A reference is removed from this list when the process's .wait or
435 # .kill method is called.
436 # XXX Should an atexit() handler be registered to kill all curently
437 # running processes? Else *could* get hangs, n'est ce pas?
438 def _registerProcess(process
):
440 log
.info("_registerprocess(process=%r)", process
)
442 # Clean up zombie processes.
443 # If the user does not call .wait() or .kill() on processes then
444 # the ProcessProxy object will not get cleaned up until Python
445 # exits and _processes goes out of scope. Under heavy usage that
446 # is a big memory waste. Cleaning up here alleviates that.
447 for p
in _processes
[:]: # use copy of _process, because we may modifiy it
449 # poll to see if is process still running
450 if sys
.platform
.startswith("win"):
455 _unregisterProcess(p
)
456 except ProcessError
, ex
:
457 if ex
.errno
== ProcessProxy
.WAIT_TIMEOUT
:
462 _processes
.append(process
)
464 def _unregisterProcess(process
):
466 log
.info("_unregisterProcess(process=%r)", process
)
468 _processes
.remove(process
)
474 def _fixupCommand(cmd
, env
=None):
475 """Fixup the command string so it is launchable via CreateProcess.
477 One cannot just launch, say "python", via CreateProcess. A full path
478 to an executable is required. In general there are two choices:
479 1. Launch the command string via the shell. The shell will find
480 the fullpath to the appropriate executable. This shell will
481 also be able to execute special shell commands, like "dir",
482 which don't map to an actual executable.
483 2. Find the fullpath to the appropriate executable manually and
486 Option (1) is preferred because you don't have to worry about not
487 exactly duplicating shell behaviour and you get the added bonus of
488 being able to launch "dir" and friends.
490 However, (1) is not always an option. Doing so when the shell is
491 command.com (as on all Win9x boxes) or when using WinNT's cmd.exe,
492 problems are created with .kill() because these shells seem to eat
493 up Ctrl-C's and Ctrl-Break's sent via
494 win32api.GenerateConsoleCtrlEvent(). Strangely this only happens
495 when spawn via this Python interface. For example, Ctrl-C get
496 through to hang.exe here:
497 C:\> ...\w9xpopen.exe "C:\WINDOWS\COMMAND.COM /c hang.exe"
500 >>> p = ProcessOpen('hang.exe')
501 # This results in the same command to CreateProcess as
505 Hence, for these platforms we fallback to option (2). Cons:
506 - cannot spawn shell commands like 'dir' directly
507 - cannot spawn batch files
509 if sys
.platform
.startswith("win"):
510 # Fixup the command string to spawn. (Lifted from
511 # posixmodule.c::_PyPopenCreateProcess() with some modifications)
512 comspec
= os
.environ
.get("COMSPEC", None)
513 win32Version
= win32api
.GetVersion()
515 raise ProcessError("Cannot locate a COMSPEC environment "\
516 "variable to use as the shell")
517 # Explicitly check if we are using COMMAND.COM. If we
518 # are then use the w9xpopen hack.
519 elif (win32Version
& 0x80000000L
== 0) and\
520 (win32Version
& 0x5L
>= 5) and\
521 os
.path
.basename(comspec
).lower() != "command.com":
522 # 2000/XP and not using command.com.
523 if '"' in cmd
or "'" in cmd
:
524 cmd
= comspec
+ ' /c "%s"' % cmd
526 cmd
= comspec
+ ' /c ' + cmd
527 elif (win32Version
& 0x80000000L
== 0) and\
528 (win32Version
& 0x5L
< 5) and\
529 os
.path
.basename(comspec
).lower() != "command.com":
530 # NT and not using command.com.
532 cmd
= _whichFirstArg(cmd
, env
)
534 raise ProcessError("Could not find a suitable executable "\
535 "to launch for '%s'. On WinNT you must manually prefix "\
536 "shell commands and batch files with 'cmd.exe /c' to "\
537 "have the shell run them." % cmd
)
539 # Oh gag, we're on Win9x and/or using COMMAND.COM. Use the
540 # workaround listed in KB: Q150956
541 w9xpopen
= os
.path
.join(
542 os
.path
.dirname(win32api
.GetModuleFileName(0)),
544 if not os
.path
.exists(w9xpopen
):
545 # Eeek - file-not-found - possibly an embedding
546 # situation - see if we can locate it in sys.exec_prefix
547 w9xpopen
= os
.path
.join(os
.path
.dirname(sys
.exec_prefix
),
549 if not os
.path
.exists(w9xpopen
):
551 "Can not locate 'w9xpopen.exe' which is needed "\
552 "for ProcessOpen to work with your shell or "\
554 ## This would be option (1):
555 #cmd = '%s "%s /c %s"'\
556 # % (w9xpopen, comspec, cmd.replace('"', '\\"'))
558 cmd
= _whichFirstArg(cmd
, env
)
560 raise ProcessError("Could not find a suitable executable "\
561 "to launch for '%s'. On Win9x you must manually prefix "\
562 "shell commands and batch files with 'command.com /c' "\
563 "to have the shell run them." % cmd
)
564 cmd
= '%s "%s"' % (w9xpopen
, cmd
.replace('"', '\\"'))
568 """Wrap a system file object, hiding some nitpicky details.
570 This class provides a Python file-like interface to either a Python
571 file object (pretty easy job), a file descriptor, or an OS-specific
572 file handle (e.g. Win32 handles to file objects on Windows). Any or
573 all of these object types may be passed to this wrapper. If more
574 than one is specified this wrapper prefers to work with certain one
576 - file descriptor (because usually this allows for
577 return-immediately-on-read-if-anything-available semantics and
578 also provides text mode translation on Windows)
579 - OS-specific handle (allows for the above read semantics)
580 - file object (buffering can cause difficulty for interacting
581 with spawned programs)
583 It also provides a place where related such objects can be kept
584 alive together to prevent premature ref-counted collection. (E.g. on
585 Windows a Python file object may be associated with a Win32 file
586 handle. If the file handle is not kept alive the Python file object
587 will cease to function.)
589 def __init__(self
, file=None, descriptor
=None, handle
=None):
591 self
._descriptor
= descriptor
592 self
._handle
= handle
594 if self
._descriptor
is not None or self
._handle
is not None:
595 self
._lineBuf
= "" # to support .readline()
600 def __getattr__(self
, name
):
601 """Forward to the underlying file object."""
602 if self
._file
is not None:
603 return getattr(self
._file
, name
)
605 raise ProcessError("no file object to pass '%s' attribute to"
608 def _win32Read(self
, nBytes
):
610 log
.info("[%s] _FileWrapper.read: waiting for read on pipe",
612 errCode
, text
= win32file
.ReadFile(self
._handle
, nBytes
)
613 except pywintypes
.error
, ex
:
614 # Ignore errors for now, like "The pipe is being closed.",
615 # etc. XXX There *may* be errors we don't want to avoid.
616 log
.info("[%s] _FileWrapper.read: error reading from pipe: %s",
619 assert errCode
== 0,\
620 "Why is 'errCode' from ReadFile non-zero? %r" % errCode
622 # Empty text signifies that the pipe has been closed on
624 log
.info("[%s] _FileWrapper.read: observed close of parent",
626 # Signal the child so it knows to stop listening.
630 log
.info("[%s] _FileWrapper.read: read %d bytes from pipe: %r",
631 id(self
), len(text
), text
)
634 def read(self
, nBytes
=-1):
635 # nBytes <= 0 means "read everything"
636 # Note that we are changing the "read everything" cue to
637 # include 0, because actually doing
638 # win32file.ReadFile(<handle>, 0) results in every subsequent
639 # read returning 0, i.e. it shuts down the pipe.
640 if self
._descriptor
is not None:
642 text
, self
._lineBuf
= self
._lineBuf
, ""
644 t
= os
.read(self
._descriptor
, 4092)
650 if len(self
._lineBuf
) >= nBytes
:
651 text
, self
._lineBuf
=\
652 self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:]
654 nBytesToGo
= nBytes
- len(self
._lineBuf
)
655 text
= self
._lineBuf
+ os
.read(self
._descriptor
,
659 elif self
._handle
is not None:
661 text
, self
._lineBuf
= self
._lineBuf
, ""
663 t
= self
._win
32Read
(4092)
669 if len(self
._lineBuf
) >= nBytes
:
670 text
, self
._lineBuf
=\
671 self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:]
673 nBytesToGo
= nBytes
- len(self
._lineBuf
)
674 text
, self
._lineBuf
=\
675 self
._lineBuf
+ self
._win
32Read
(nBytesToGo
), ""
677 elif self
._file
is not None:
678 return self
._file
.read(nBytes
)
680 raise "FileHandle.read: no handle to read with"
683 if self
._descriptor
is not None or self
._handle
is not None:
685 #XXX This is not portable to the Mac.
686 idx
= self
._lineBuf
.find('\n')
688 line
, self
._lineBuf
=\
689 self
._lineBuf
[:idx
+1], self
._lineBuf
[idx
+1:]
692 lengthBefore
= len(self
._lineBuf
)
694 if len(t
) <= lengthBefore
: # no new data was read
695 line
, self
._lineBuf
= self
._lineBuf
, ""
700 elif self
._file
is not None:
701 return self
._file
.readline()
703 raise "FileHandle.readline: no handle to read with"
706 if self
._descriptor
is not None or self
._handle
is not None:
709 line
= self
.readline()
715 elif self
._file
is not None:
716 return self
._file
.readlines()
718 raise "FileHandle.readline: no handle to read with"
720 def write(self
, text
):
721 if self
._descriptor
is not None:
722 os
.write(self
._descriptor
, text
)
723 elif self
._handle
is not None:
725 errCode
, nBytesWritten
= win32file
.WriteFile(self
._handle
, text
)
726 except pywintypes
.error
, ex
:
727 # Ingore errors like "The pipe is being closed.", for
729 log
.info("[%s] _FileWrapper.write: error writing to pipe, "\
732 assert errCode
== 0,\
733 "Why is 'errCode' from WriteFile non-zero? %r" % errCode
734 if not nBytesWritten
:
735 # No bytes written signifies that the pipe has been
736 # closed on the child's end.
737 log
.info("[%s] _FileWrapper.write: observed close of pipe",
741 log
.info("[%s] _FileWrapper.write: wrote %d bytes to pipe: %r",
742 id(self
), len(text
), text
)
743 elif self
._file
is not None:
744 self
._file
.write(text
)
746 raise "FileHandle.write: nothing to write with"
749 """Close all associated file objects and handles."""
750 log
.debug("[%s] _FileWrapper.close()", id(self
))
753 if self
._file
is not None:
754 log
.debug("[%s] _FileWrapper.close: close file", id(self
))
756 log
.debug("[%s] _FileWrapper.close: done file close", id(self
))
757 if self
._descriptor
is not None:
759 os
.close(self
._descriptor
)
762 # Ignore: OSError: [Errno 9] Bad file descriptor
763 # XXX *Should* we be ignoring this? It appears very
764 # *in*frequently in test_wait.py.
765 log
.debug("[%s] _FileWrapper.close: closing "\
766 "descriptor raised OSError", id(self
))
769 if self
._handle
is not None:
770 log
.debug("[%s] _FileWrapper.close: close handle", id(self
))
772 win32api
.CloseHandle(self
._handle
)
773 except win32api
.error
:
774 log
.debug("[%s] _FileWrapper.close: closing handle raised",
777 log
.debug("[%s] _FileWrapper.close: done closing handle",
781 return "<_FileWrapper: file:%r fd:%r os_handle:%r>"\
782 % (self
._file
, self
._descriptor
, self
._handle
)
785 class _CountingCloser
:
786 """Call .close() on the given object after own .close() is called
787 the precribed number of times.
789 def __init__(self
, objectsToClose
, count
):
791 "objectsToClose" is a list of object on which to call .close().
792 "count" is the number of times this object's .close() method
793 must be called before .close() is called on the given objects.
795 self
.objectsToClose
= objectsToClose
798 raise ProcessError("illegal 'count' value: %s" % self
.count
)
802 log
.debug("[%d] _CountingCloser.close(): count=%d", id(self
),
805 for objectToClose
in self
.objectsToClose
:
806 objectToClose
.close()
810 #---- public interface
815 One can optionally specify the starting working directory, the
816 process environment, and std handles to have the child process
817 inherit (all defaults are the parent's current settings). 'wait' and
818 'kill' method allow for control of the child's termination.
821 # - Rename this or merge it with ProcessOpen somehow.
823 if sys
.platform
.startswith("win"):
824 # .wait() argument constants
825 INFINITE
= win32event
.INFINITE
826 # .wait() return error codes
827 WAIT_FAILED
= win32event
.WAIT_FAILED
828 WAIT_TIMEOUT
= win32event
.WAIT_TIMEOUT
829 # creation "flags" constants
830 # XXX Should drop these and just document usage of
831 # win32process.CREATE_* constants on windows.
832 CREATE_NEW_CONSOLE
= win32process
.CREATE_NEW_CONSOLE
834 # .wait() argument constants
836 # .wait() return error codes
839 # creation "flags" constants
840 CREATE_NEW_CONSOLE
= 0x10 # same as win32process.CREATE_NEW_CONSOLE
842 def __init__(self
, cmd
, cwd
=None, env
=None, flags
=0):
843 """Create a child process.
845 "cmd" is a command string or argument vector to spawn.
846 "cwd" is a working directory in which to start the child process.
847 "env" is an environment dictionary for the child.
848 "flags" are system-specific process creation flags. On Windows
849 this can be a bitwise-OR of any of the win32process.CREATE_*
850 constants (Note: win32process.CREATE_NEW_PROCESS_GROUP is always
851 OR'd in). On Unix, this is currently ignored.
853 log
.info("Process.__init__(cmd=%r, cwd=%r, env=%r, flags=%r)",
854 cmd
, cwd
, env
, flags
)
857 raise ProcessError("You must specify a command.")
861 if sys
.platform
.startswith("win"):
862 self
._flags |
= win32process
.CREATE_NEW_PROCESS_GROUP
864 if sys
.platform
.startswith("win"):
865 self
._startOnWindows
()
867 self
.__retvalCache
= None
870 def _runChildOnUnix(self
):
871 #XXX Errors running the child do *not* get communicated back.
873 #XXX Perhaps we should *always* prefix with '/bin/sh -c'? There is a
874 # disparity btwn how this works on Linux and Windows.
875 if isinstance(self
._cmd
, types
.StringTypes
):
876 # This is easier than trying to reproduce shell interpretation to
877 # separate the arguments.
878 cmd
= ['/bin/sh', '-c', self
._cmd
]
882 # Close all file descriptors (except std*) inherited from the parent.
883 MAXFD
= 256 # Max number of file descriptors (os.getdtablesize()???)
884 for i
in range(3, MAXFD
):
892 os
.execvpe(cmd
[0], cmd
, self
._env
)
894 os
.execvp(cmd
[0], cmd
)
896 os
._exit
(1) # Should never get here.
898 def _forkAndExecChildOnUnix(self
):
899 """Fork and start the child process.
901 Sets self._pid as a side effect.
905 self
._runChildOnUnix
()
909 def _startOnUnix(self
):
915 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
916 self
._forkAndExecChildOnUnix
()
922 def _startOnWindows(self
):
923 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
924 # And arg vector was passed in.
925 cmd
= _joinArgv(self
._cmd
)
929 si
= win32process
.STARTUPINFO()
930 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
931 si
.wShowWindow
= SW_SHOWDEFAULT
933 if not (self
._flags
& self
.CREATE_NEW_CONSOLE
):
935 # We cannot then use _fixupCommand because this will cause a
936 # shell to be openned as the command is launched. Therefore need
937 # to ensure be have the full path to the executable to launch.
939 cmd
= _whichFirstArg(cmd
, self
._env
)
941 # Could not find the command, perhaps it is an internal
942 # shell command -- fallback to _fixupCommand
943 cmd
= _fixupCommand(cmd
, self
._env
)
945 cmd
= _fixupCommand(cmd
, self
._env
)
946 log
.debug("cmd = %r", cmd
)
948 # Start the child process.
950 self
._hProcess
, self
._hThread
, self
._processId
, self
._threadId\
951 = _SaferCreateProcess(
954 None, # process security attributes
955 None, # primary thread security attributes
956 0, # handles are inherited
957 self
._flags
, # creation flags
958 self
._env
, # environment
959 self
._cwd
, # current working directory
960 si
) # STARTUPINFO pointer
961 win32api
.CloseHandle(self
._hThread
)
962 except win32api
.error
, ex
:
963 raise ProcessError(msg
="Error creating process for '%s': %s"\
967 def wait(self
, timeout
=None):
968 """Wait for the started process to complete.
970 "timeout" (on Windows) is a floating point number of seconds after
971 which to timeout. Default is win32event.INFINITE.
972 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
973 (os.WNOHANG may be used to return immediately if the process has
974 not exited). Default is 0, i.e. wait forever.
976 If the wait time's out it will raise a ProcessError. Otherwise it
977 will return the child's exit value (on Windows) or the child's exit
978 status excoded as per os.waitpid() (on Linux):
979 "a 16-bit number, whose low byte is the signal number that killed
980 the process, and whose high byte is the exit status (if the
981 signal number is zero); the high bit of the low byte is set if a
982 core file was produced."
983 In the latter case, use the os.W*() methods to interpret the return
986 # XXX Or should returning the exit value be move out to another
987 # function as on Win32 process control? If so, then should
988 # perhaps not make WaitForSingleObject semantic transformation.
989 if sys
.platform
.startswith("win"):
991 timeout
= win32event
.INFINITE
993 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
995 rc
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
)
996 if rc
== win32event
.WAIT_FAILED
:
997 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
998 "terminate: %r" % self
._cmd
, rc
)
999 elif rc
== win32event
.WAIT_TIMEOUT
:
1000 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
1001 "terminate: %r" % self
._cmd
, rc
)
1003 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
1005 # os.waitpid() will raise:
1006 # OSError: [Errno 10] No child processes
1007 # on subsequent .wait() calls. Change these semantics to have
1008 # subsequent .wait() calls return the exit status and return
1009 # immediately without raising an exception.
1010 # (XXX It would require synchronization code to handle the case
1011 # of multiple simultaneous .wait() requests, however we can punt
1012 # on that because it is moot while Linux still has the problem
1013 # for which _ThreadFixer() exists.)
1014 if self
.__retvalCache
is not None:
1015 retval
= self
.__retvalCache
1019 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1020 if pid
== self
._pid
:
1021 self
.__retvalCache
= retval
= sts
1023 raise ProcessError("Wait for process timed out.",
1027 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1030 "exitCode" [deprecated, not supported] (Windows only) is the
1031 code the terminated process should exit with.
1032 "gracePeriod" (Windows only) is a number of seconds the process is
1033 allowed to shutdown with a WM_CLOSE signal before a hard
1034 terminate is called.
1035 "sig" (Unix only) is the signal to use to kill the process. Defaults
1036 to signal.SIGKILL. See os.kill() for more information.
1039 Try for an orderly shutdown via WM_CLOSE. If still running
1040 after gracePeriod (1 sec. default), terminate.
1042 if sys
.platform
.startswith("win"):
1044 # Send WM_CLOSE to windows in this process group.
1045 win32gui
.EnumWindows(self
._close
_, 0)
1047 # Send Ctrl-Break signal to all processes attached to this
1048 # console. This is supposed to trigger shutdown handlers in
1049 # each of the processes.
1051 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1053 except AttributeError:
1054 log
.warn("The win32api module does not have "\
1055 "GenerateConsoleCtrlEvent(). This may mean that "\
1056 "parts of this process group have NOT been killed.")
1057 except win32api
.error
, ex
:
1058 if ex
.args
[0] not in (6, 87):
1059 # Ignore the following:
1060 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1061 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1062 # Get error 6 if there is no console.
1065 # Last resort: call TerminateProcess if it has not yet.
1068 self
.wait(gracePeriod
)
1069 except ProcessError
, ex
:
1070 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1071 win32process
.TerminateProcess(self
._hProcess
, -1)
1072 win32api
.Sleep(100) # wait for resources to be released
1076 sig
= signal
.SIGKILL
1078 os
.kill(self
._pid
, sig
)
1081 # Ignore: OSError: [Errno 3] No such process
1084 def _close_(self
, hwnd
, dummy
):
1085 """Callback used by .kill() on Windows.
1087 EnumWindows callback - sends WM_CLOSE to any window owned by this
1090 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1091 if processId
== self
._processId
:
1093 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1096 class ProcessOpen(Process
):
1097 """Create a process and setup pipes to it standard handles.
1099 This is a super popen3.
1102 # - Share some implementation with Process and ProcessProxy.
1105 def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None):
1106 """Create a Process with proxy threads for each std handle.
1108 "cmd" is the command string or argument vector to run.
1109 "mode" (Windows only) specifies whether the pipes used to communicate
1110 with the child are openned in text, 't', or binary, 'b', mode.
1111 This is ignored on platforms other than Windows. Default is 't'.
1112 "cwd" optionally specifies the directory in which the child process
1113 should be started. Default is None, a.k.a. inherits the cwd from
1115 "env" is optionally a mapping specifying the environment in which to
1116 start the child. Default is None, a.k.a. inherits the environment
1119 # Keep a reference to ensure it is around for this object's destruction.
1121 log
.info("ProcessOpen.__init__(cmd=%r, mode=%r, cwd=%r, env=%r)",
1122 cmd
, mode
, cwd
, env
)
1125 raise ProcessError("You must specify a command.")
1129 if self
._mode
not in ('t', 'b'):
1130 raise ProcessError("'mode' must be 't' or 'b'.")
1133 if sys
.platform
.startswith("win"):
1134 self
._startOnWindows
()
1136 self
.__retvalCache
= None
1139 _registerProcess(self
)
1142 #XXX Should probably not rely upon this.
1143 logres
.info("[%s] ProcessOpen.__del__()", id(self
))
1145 del self
.__log
# drop reference
1148 if not self
._closed
:
1149 self
.__log
.info("[%s] ProcessOpen.close()" % id(self
))
1151 # Ensure that all IOBuffer's are closed. If they are not, these
1154 self
.__log
.info("[%s] ProcessOpen: closing stdin (%r)."\
1155 % (id(self
), self
.stdin
))
1157 except AttributeError:
1158 # May not have gotten far enough in the __init__ to set
1162 self
.__log
.info("[%s] ProcessOpen: closing stdout (%r)."\
1163 % (id(self
), self
.stdout
))
1165 except AttributeError:
1166 # May not have gotten far enough in the __init__ to set
1170 self
.__log
.info("[%s] ProcessOpen: closing stderr (%r)."\
1171 % (id(self
), self
.stderr
))
1173 except AttributeError:
1174 # May not have gotten far enough in the __init__ to set
1180 def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
,
1182 """Fork and start the child process.
1184 Sets self._pid as a side effect.
1187 if pid
== 0: # child
1188 os
.dup2(fdChildStdinRd
, 0)
1189 os
.dup2(fdChildStdoutWr
, 1)
1190 os
.dup2(fdChildStderrWr
, 2)
1191 self
._runChildOnUnix
()
1195 def _startOnUnix(self
):
1196 # Create pipes for std handles.
1197 fdChildStdinRd
, fdChildStdinWr
= os
.pipe()
1198 fdChildStdoutRd
, fdChildStdoutWr
= os
.pipe()
1199 fdChildStderrRd
, fdChildStderrWr
= os
.pipe()
1202 oldDir
= os
.getcwd()
1206 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
1207 self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
,
1212 os
.close(fdChildStdinRd
)
1213 os
.close(fdChildStdoutWr
)
1214 os
.close(fdChildStderrWr
)
1216 self
.stdin
= _FileWrapper(descriptor
=fdChildStdinWr
)
1217 logres
.info("[%s] ProcessOpen._start(): create child stdin: %r",
1218 id(self
), self
.stdin
)
1219 self
.stdout
= _FileWrapper(descriptor
=fdChildStdoutRd
)
1220 logres
.info("[%s] ProcessOpen._start(): create child stdout: %r",
1221 id(self
), self
.stdout
)
1222 self
.stderr
= _FileWrapper(descriptor
=fdChildStderrRd
)
1223 logres
.info("[%s] ProcessOpen._start(): create child stderr: %r",
1224 id(self
), self
.stderr
)
1226 def _startOnWindows(self
):
1227 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
1228 # An arg vector was passed in.
1229 cmd
= _joinArgv(self
._cmd
)
1233 # Create pipes for std handles.
1234 # (Set the bInheritHandle flag so pipe handles are inherited.)
1235 saAttr
= pywintypes
.SECURITY_ATTRIBUTES()
1236 saAttr
.bInheritHandle
= 1
1237 #XXX Should maybe try with os.pipe. Dunno what that does for
1238 # inheritability though.
1239 hChildStdinRd
, hChildStdinWr
= win32pipe
.CreatePipe(saAttr
, 0)
1240 hChildStdoutRd
, hChildStdoutWr
= win32pipe
.CreatePipe(saAttr
, 0)
1241 hChildStderrRd
, hChildStderrWr
= win32pipe
.CreatePipe(saAttr
, 0)
1244 # Duplicate the parent ends of the pipes so they are not
1246 hChildStdinWrDup
= win32api
.DuplicateHandle(
1247 win32api
.GetCurrentProcess(),
1249 win32api
.GetCurrentProcess(),
1252 DUPLICATE_SAME_ACCESS
)
1253 win32api
.CloseHandle(hChildStdinWr
)
1254 self
._hChildStdinWr
= hChildStdinWrDup
1255 hChildStdoutRdDup
= win32api
.DuplicateHandle(
1256 win32api
.GetCurrentProcess(),
1258 win32api
.GetCurrentProcess(),
1261 DUPLICATE_SAME_ACCESS
)
1262 win32api
.CloseHandle(hChildStdoutRd
)
1263 self
._hChildStdoutRd
= hChildStdoutRdDup
1264 hChildStderrRdDup
= win32api
.DuplicateHandle(
1265 win32api
.GetCurrentProcess(),
1267 win32api
.GetCurrentProcess(),
1270 DUPLICATE_SAME_ACCESS
)
1271 win32api
.CloseHandle(hChildStderrRd
)
1272 self
._hChildStderrRd
= hChildStderrRdDup
1274 # Set the translation mode and buffering.
1275 if self
._mode
== 't':
1279 fdChildStdinWr
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
)
1280 fdChildStdoutRd
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
)
1281 fdChildStderrRd
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
)
1283 self
.stdin
= _FileWrapper(descriptor
=fdChildStdinWr
,
1284 handle
=self
._hChildStdinWr
)
1285 logres
.info("[%s] ProcessOpen._start(): create child stdin: %r",
1286 id(self
), self
.stdin
)
1287 self
.stdout
= _FileWrapper(descriptor
=fdChildStdoutRd
,
1288 handle
=self
._hChildStdoutRd
)
1289 logres
.info("[%s] ProcessOpen._start(): create child stdout: %r",
1290 id(self
), self
.stdout
)
1291 self
.stderr
= _FileWrapper(descriptor
=fdChildStderrRd
,
1292 handle
=self
._hChildStderrRd
)
1293 logres
.info("[%s] ProcessOpen._start(): create child stderr: %r",
1294 id(self
), self
.stderr
)
1296 # Start the child process.
1297 si
= win32process
.STARTUPINFO()
1298 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
1299 si
.wShowWindow
= 0 # SW_HIDE
1300 si
.hStdInput
= hChildStdinRd
1301 si
.hStdOutput
= hChildStdoutWr
1302 si
.hStdError
= hChildStderrWr
1303 si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
1305 cmd
= _fixupCommand(cmd
, self
._env
)
1307 creationFlags
= win32process
.CREATE_NEW_PROCESS_GROUP
1309 self
._hProcess
, hThread
, self
._processId
, threadId\
1310 = _SaferCreateProcess(
1313 None, # process security attributes
1314 None, # primary thread security attributes
1315 1, # handles are inherited
1316 creationFlags
, # creation flags
1317 self
._env
, # environment
1318 self
._cwd
, # current working directory
1319 si
) # STARTUPINFO pointer
1320 except win32api
.error
, ex
:
1321 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0])
1322 win32api
.CloseHandle(hThread
)
1325 # Close child ends of pipes on the parent's side (the
1326 # parent's ends of the pipe are closed in the _FileWrappers.)
1327 win32file
.CloseHandle(hChildStdinRd
)
1328 win32file
.CloseHandle(hChildStdoutWr
)
1329 win32file
.CloseHandle(hChildStderrWr
)
1331 def wait(self
, timeout
=None):
1332 """Wait for the started process to complete.
1334 "timeout" (on Windows) is a floating point number of seconds after
1335 which to timeout. Default is win32event.INFINITE.
1336 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
1337 (os.WNOHANG may be used to return immediately if the process has
1338 not exited). Default is 0, i.e. wait forever.
1340 If the wait time's out it will raise a ProcessError. Otherwise it
1341 will return the child's exit value (on Windows) or the child's exit
1342 status excoded as per os.waitpid() (on Linux):
1343 "a 16-bit number, whose low byte is the signal number that killed
1344 the process, and whose high byte is the exit status (if the
1345 signal number is zero); the high bit of the low byte is set if a
1346 core file was produced."
1347 In the latter case, use the os.W*() methods to interpret the return
1350 # XXX Or should returning the exit value be move out to another
1351 # function as on Win32 process control? If so, then should
1352 # perhaps not make WaitForSingleObject semantic
1355 # - Need to rationalize the .wait() API for Windows vs. Unix.
1356 # It is a real pain in the current situation.
1357 if sys
.platform
.startswith("win"):
1359 timeout
= win32event
.INFINITE
1361 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
1363 #rc = win32event.WaitForSingleObject(self._hProcess, timeout)
1364 rc
= win32event
.WaitForSingleObject(self
._hProcess
, int(timeout
)) # MATT -- Making timeout an integer
1365 if rc
== win32event
.WAIT_FAILED
:
1366 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
1367 "terminate: %r" % self
._cmd
, rc
)
1368 elif rc
== win32event
.WAIT_TIMEOUT
:
1369 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
1370 "terminate: %r" % self
._cmd
, rc
)
1372 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
1374 # os.waitpid() will raise:
1375 # OSError: [Errno 10] No child processes
1376 # on subsequent .wait() calls. Change these semantics to have
1377 # subsequent .wait() calls return the exit status and return
1378 # immediately without raising an exception.
1379 # (XXX It would require synchronization code to handle the case
1380 # of multiple simultaneous .wait() requests, however we can punt
1381 # on that because it is moot while Linux still has the problem
1382 # for which _ThreadFixer() exists.)
1383 if self
.__retvalCache
is not None:
1384 retval
= self
.__retvalCache
1388 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1389 if pid
== self
._pid
:
1390 self
.__retvalCache
= retval
= sts
1392 raise ProcessError("Wait for process timed out.",
1394 _unregisterProcess(self
)
1397 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1400 "exitCode" [deprecated, not supported] (Windows only) is the
1401 code the terminated process should exit with.
1402 "gracePeriod" (Windows only) is a number of seconds the process is
1403 allowed to shutdown with a WM_CLOSE signal before a hard
1404 terminate is called.
1405 "sig" (Unix only) is the signal to use to kill the process. Defaults
1406 to signal.SIGKILL. See os.kill() for more information.
1409 Try for an orderly shutdown via WM_CLOSE. If still running
1410 after gracePeriod (1 sec. default), terminate.
1412 if sys
.platform
.startswith("win"):
1414 # Send WM_CLOSE to windows in this process group.
1415 win32gui
.EnumWindows(self
._close
_, 0)
1417 # Send Ctrl-Break signal to all processes attached to this
1418 # console. This is supposed to trigger shutdown handlers in
1419 # each of the processes.
1421 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1423 except AttributeError:
1424 log
.warn("The win32api module does not have "\
1425 "GenerateConsoleCtrlEvent(). This may mean that "\
1426 "parts of this process group have NOT been killed.")
1427 except win32api
.error
, ex
:
1428 if ex
.args
[0] not in (6, 87):
1429 # Ignore the following:
1430 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1431 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1432 # Get error 6 if there is no console.
1435 # Last resort: call TerminateProcess if it has not yet.
1438 self
.wait(gracePeriod
)
1439 except ProcessError
, ex
:
1440 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1441 win32process
.TerminateProcess(self
._hProcess
, -1)
1442 win32api
.Sleep(100) # wait for resources to be released
1446 sig
= signal
.SIGKILL
1448 os
.kill(self
._pid
, sig
)
1451 # Ignore: OSError: [Errno 3] No such process
1454 _unregisterProcess(self
)
1456 def _close_(self
, hwnd
, dummy
):
1457 """Callback used by .kill() on Windows.
1459 EnumWindows callback - sends WM_CLOSE to any window owned by this
1462 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1463 if processId
== self
._processId
:
1465 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1468 class ProcessProxy(Process
):
1469 """Create a process and proxy communication via the standard handles.
1471 #XXX To add to docstring:
1472 # - stdout/stderr proxy handling
1473 # - stdin proxy handling
1475 # - how to .start(), i.e. basic usage rules
1476 # - mention that pased in stdin/stdout/stderr objects have to
1477 # implement at least .write (is .write correct for stdin)?
1478 # - if you pass in stdin, stdout, and/or stderr streams it is the
1479 # user's responsibility to close them afterwards.
1480 # - 'cmd' arg can be a command string or an arg vector
1483 # - .suspend() and .resume()? See Win32::Process Perl module.
1485 def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None,
1486 stdin
=None, stdout
=None, stderr
=None):
1487 """Create a Process with proxy threads for each std handle.
1489 "cmd" is the command string or argument vector to run.
1490 "mode" (Windows only) specifies whether the pipes used to communicate
1491 with the child are openned in text, 't', or binary, 'b', mode.
1492 This is ignored on platforms other than Windows. Default is 't'.
1493 "cwd" optionally specifies the directory in which the child process
1494 should be started. Default is None, a.k.a. inherits the cwd from
1496 "env" is optionally a mapping specifying the environment in which to
1497 start the child. Default is None, a.k.a. inherits the environment
1499 "stdin", "stdout", "stderr" can be used to specify objects with
1500 file-like interfaces to handle read (stdout/stderr) and write
1501 (stdin) events from the child. By default a process.IOBuffer
1502 instance is assigned to each handler. IOBuffer may be
1503 sub-classed. See the IOBuffer doc string for more information.
1505 # Keep a reference to ensure it is around for this object's destruction.
1507 log
.info("ProcessProxy.__init__(cmd=%r, mode=%r, cwd=%r, env=%r, "\
1508 "stdin=%r, stdout=%r, stderr=%r)",
1509 cmd
, mode
, cwd
, env
, stdin
, stdout
, stderr
)
1512 raise ProcessError("You must specify a command.")
1514 if self
._mode
not in ('t', 'b'):
1515 raise ProcessError("'mode' must be 't' or 'b'.")
1519 self
.stdin
= IOBuffer(name
='<stdin>')
1523 self
.stdout
= IOBuffer(name
='<stdout>')
1525 self
.stdout
= stdout
1527 self
.stderr
= IOBuffer(name
='<stderr>')
1529 self
.stderr
= stderr
1532 if sys
.platform
.startswith("win"):
1533 self
._startOnWindows
()
1535 self
.__retvalCache
= None
1538 _registerProcess(self
)
1541 #XXX Should probably not rely upon this.
1542 logres
.info("[%s] ProcessProxy.__del__()", id(self
))
1544 del self
.__log
# drop reference
1547 if not self
._closed
:
1548 self
.__log
.info("[%s] ProcessProxy.close()" % id(self
))
1550 # Ensure that all IOBuffer's are closed. If they are not, these
1552 self
.__log
.info("[%s] ProcessProxy: closing stdin (%r)."\
1553 % (id(self
), self
.stdin
))
1556 self
._stdinProxy
.join()
1557 except AttributeError:
1558 # May not have gotten far enough in the __init__ to set
1561 self
.__log
.info("[%s] ProcessProxy: closing stdout (%r)."\
1562 % (id(self
), self
.stdout
))
1565 if self
._stdoutProxy
is not threading
.currentThread():
1566 self
._stdoutProxy
.join()
1567 except AttributeError:
1568 # May not have gotten far enough in the __init__ to set
1571 self
.__log
.info("[%s] ProcessProxy: closing stderr (%r)."\
1572 % (id(self
), self
.stderr
))
1575 if self
._stderrProxy
is not threading
.currentThread():
1576 self
._stderrProxy
.join()
1577 except AttributeError:
1578 # May not have gotten far enough in the __init__ to set
1584 def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
,
1586 """Fork and start the child process.
1588 Sets self._pid as a side effect.
1591 if pid
== 0: # child
1592 os
.dup2(fdChildStdinRd
, 0)
1593 os
.dup2(fdChildStdoutWr
, 1)
1594 os
.dup2(fdChildStderrWr
, 2)
1595 self
._runChildOnUnix
()
1599 def _startOnUnix(self
):
1600 # Create pipes for std handles.
1601 fdChildStdinRd
, fdChildStdinWr
= os
.pipe()
1602 fdChildStdoutRd
, fdChildStdoutWr
= os
.pipe()
1603 fdChildStderrRd
, fdChildStderrWr
= os
.pipe()
1606 oldDir
= os
.getcwd()
1610 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
)
1611 self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
,
1616 os
.close(fdChildStdinRd
)
1617 os
.close(fdChildStdoutWr
)
1618 os
.close(fdChildStderrWr
)
1620 childStdin
= _FileWrapper(descriptor
=fdChildStdinWr
)
1621 logres
.info("[%s] ProcessProxy._start(): create child stdin: %r",
1622 id(self
), childStdin
)
1623 childStdout
= _FileWrapper(descriptor
=fdChildStdoutRd
)
1624 logres
.info("[%s] ProcessProxy._start(): create child stdout: %r",
1625 id(self
), childStdout
)
1626 childStderr
= _FileWrapper(descriptor
=fdChildStderrRd
)
1627 logres
.info("[%s] ProcessProxy._start(): create child stderr: %r",
1628 id(self
), childStderr
)
1630 # Create proxy threads for the out pipes.
1631 self
._stdinProxy
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>')
1632 self
._stdinProxy
.start()
1633 # Clean up the parent's side of <stdin> when it is observed that
1634 # the child has closed its side of <stdout> and <stderr>. (This
1635 # is one way of determining when it is appropriate to clean up
1636 # this pipe, with compromises. See the discussion at the top of
1638 closer
= _CountingCloser([self
.stdin
, childStdin
, self
], 2)
1639 self
._stdoutProxy
= _OutFileProxy(childStdout
, self
.stdout
,
1642 self
._stdoutProxy
.start()
1643 self
._stderrProxy
= _OutFileProxy(childStderr
, self
.stderr
,
1646 self
._stderrProxy
.start()
1648 def _startOnWindows(self
):
1649 if type(self
._cmd
) in (types
.ListType
, types
.TupleType
):
1650 # An arg vector was passed in.
1651 cmd
= _joinArgv(self
._cmd
)
1655 # Create pipes for std handles.
1656 # (Set the bInheritHandle flag so pipe handles are inherited.)
1657 saAttr
= pywintypes
.SECURITY_ATTRIBUTES()
1658 saAttr
.bInheritHandle
= 1
1659 #XXX Should maybe try with os.pipe. Dunno what that does for
1660 # inheritability though.
1661 hChildStdinRd
, hChildStdinWr
= win32pipe
.CreatePipe(saAttr
, 0)
1662 hChildStdoutRd
, hChildStdoutWr
= win32pipe
.CreatePipe(saAttr
, 0)
1663 hChildStderrRd
, hChildStderrWr
= win32pipe
.CreatePipe(saAttr
, 0)
1666 # Duplicate the parent ends of the pipes so they are not
1668 hChildStdinWrDup
= win32api
.DuplicateHandle(
1669 win32api
.GetCurrentProcess(),
1671 win32api
.GetCurrentProcess(),
1674 DUPLICATE_SAME_ACCESS
)
1675 win32api
.CloseHandle(hChildStdinWr
)
1676 self
._hChildStdinWr
= hChildStdinWrDup
1677 hChildStdoutRdDup
= win32api
.DuplicateHandle(
1678 win32api
.GetCurrentProcess(),
1680 win32api
.GetCurrentProcess(),
1683 DUPLICATE_SAME_ACCESS
)
1684 win32api
.CloseHandle(hChildStdoutRd
)
1685 self
._hChildStdoutRd
= hChildStdoutRdDup
1686 hChildStderrRdDup
= win32api
.DuplicateHandle(
1687 win32api
.GetCurrentProcess(),
1689 win32api
.GetCurrentProcess(),
1692 DUPLICATE_SAME_ACCESS
)
1693 win32api
.CloseHandle(hChildStderrRd
)
1694 self
._hChildStderrRd
= hChildStderrRdDup
1696 # Set the translation mode.
1697 if self
._mode
== 't':
1703 fdChildStdinWr
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
)
1704 fdChildStdoutRd
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
)
1705 fdChildStderrRd
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
)
1707 childStdin
= _FileWrapper(descriptor
=fdChildStdinWr
,
1708 handle
=self
._hChildStdinWr
)
1709 logres
.info("[%s] ProcessProxy._start(): create child stdin: %r",
1710 id(self
), childStdin
)
1711 childStdout
= _FileWrapper(descriptor
=fdChildStdoutRd
,
1712 handle
=self
._hChildStdoutRd
)
1713 logres
.info("[%s] ProcessProxy._start(): create child stdout: %r",
1714 id(self
), childStdout
)
1715 childStderr
= _FileWrapper(descriptor
=fdChildStderrRd
,
1716 handle
=self
._hChildStderrRd
)
1717 logres
.info("[%s] ProcessProxy._start(): create child stderr: %r",
1718 id(self
), childStderr
)
1720 # Start the child process.
1721 si
= win32process
.STARTUPINFO()
1722 si
.dwFlags
= win32process
.STARTF_USESHOWWINDOW
1723 si
.wShowWindow
= 0 # SW_HIDE
1724 si
.hStdInput
= hChildStdinRd
1725 si
.hStdOutput
= hChildStdoutWr
1726 si
.hStdError
= hChildStderrWr
1727 si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
1729 cmd
= _fixupCommand(cmd
, self
._env
)
1730 log
.debug("cmd = %r", cmd
)
1732 creationFlags
= win32process
.CREATE_NEW_PROCESS_GROUP
1734 self
._hProcess
, hThread
, self
._processId
, threadId\
1735 = _SaferCreateProcess(
1738 None, # process security attributes
1739 None, # primary thread security attributes
1740 1, # handles are inherited
1741 creationFlags
, # creation flags
1742 self
._env
, # environment
1743 self
._cwd
, # current working directory
1744 si
) # STARTUPINFO pointer
1745 except win32api
.error
, ex
:
1746 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0])
1747 win32api
.CloseHandle(hThread
)
1750 # Close child ends of pipes on the parent's side (the
1751 # parent's ends of the pipe are closed in the _FileWrappers.)
1752 win32file
.CloseHandle(hChildStdinRd
)
1753 win32file
.CloseHandle(hChildStdoutWr
)
1754 win32file
.CloseHandle(hChildStderrWr
)
1756 # Create proxy threads for the pipes.
1757 self
._stdinProxy
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>')
1758 self
._stdinProxy
.start()
1759 # Clean up the parent's side of <stdin> when it is observed that
1760 # the child has closed its side of <stdout>. (This is one way of
1761 # determining when it is appropriate to clean up this pipe, with
1762 # compromises. See the discussion at the top of this module.)
1763 self
._stdoutProxy
= _OutFileProxy(childStdout
, self
.stdout
,
1764 [self
.stdin
, childStdin
, self
],
1766 self
._stdoutProxy
.start()
1767 self
._stderrProxy
= _OutFileProxy(childStderr
, self
.stderr
,
1769 self
._stderrProxy
.start()
1771 def wait(self
, timeout
=None):
1772 """Wait for the started process to complete.
1774 "timeout" (on Windows) is a floating point number of seconds after
1775 which to timeout. Default is win32event.INFINITE.
1776 "timeout" (on Unix) is akin to the os.waitpid() "options" argument
1777 (os.WNOHANG may be used to return immediately if the process has
1778 not exited). Default is 0, i.e. wait forever.
1780 If the wait time's out it will raise a ProcessError. Otherwise it
1781 will return the child's exit value (on Windows) or the child's exit
1782 status excoded as per os.waitpid() (on Linux):
1783 "a 16-bit number, whose low byte is the signal number that killed
1784 the process, and whose high byte is the exit status (if the
1785 signal number is zero); the high bit of the low byte is set if a
1786 core file was produced."
1787 In the latter case, use the os.W*() methods to interpret the return
1790 # XXX Or should returning the exit value be move out to another
1791 # function as on Win32 process control? If so, then should
1792 # perhaps not make WaitForSingleObject semantic transformation.
1793 if sys
.platform
.startswith("win"):
1795 timeout
= win32event
.INFINITE
1797 timeout
= timeout
* 1000.0 # Win32 API's timeout is in millisecs
1799 rc
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
)
1800 if rc
== win32event
.WAIT_FAILED
:
1801 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
1802 "terminate: %r" % self
._cmd
, rc
)
1803 elif rc
== win32event
.WAIT_TIMEOUT
:
1804 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
1805 "terminate: %r" % self
._cmd
, rc
)
1807 retval
= win32process
.GetExitCodeProcess(self
._hProcess
)
1809 # os.waitpid() will raise:
1810 # OSError: [Errno 10] No child processes
1811 # on subsequent .wait() calls. Change these semantics to have
1812 # subsequent .wait() calls return the exit status and return
1813 # immediately without raising an exception.
1814 # (XXX It would require synchronization code to handle the case
1815 # of multiple simultaneous .wait() requests, however we can punt
1816 # on that because it is moot while Linux still has the problem
1817 # for which _ThreadFixer() exists.)
1818 if self
.__retvalCache
is not None:
1819 retval
= self
.__retvalCache
1823 pid
, sts
= os
.waitpid(self
._pid
, timeout
)
1824 if pid
== self
._pid
:
1825 self
.__retvalCache
= retval
= sts
1827 raise ProcessError("Wait for process timed out.",
1829 _unregisterProcess(self
)
1832 def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None):
1835 "exitCode" [deprecated, not supported] (Windows only) is the
1836 code the terminated process should exit with.
1837 "gracePeriod" (Windows only) is a number of seconds the process is
1838 allowed to shutdown with a WM_CLOSE signal before a hard
1839 terminate is called.
1840 "sig" (Unix only) is the signal to use to kill the process. Defaults
1841 to signal.SIGKILL. See os.kill() for more information.
1844 Try for an orderly shutdown via WM_CLOSE. If still running
1845 after gracePeriod (1 sec. default), terminate.
1847 if sys
.platform
.startswith("win"):
1849 # Send WM_CLOSE to windows in this process group.
1850 win32gui
.EnumWindows(self
._close
_, 0)
1852 # Send Ctrl-Break signal to all processes attached to this
1853 # console. This is supposed to trigger shutdown handlers in
1854 # each of the processes.
1856 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
,
1858 except AttributeError:
1859 log
.warn("The win32api module does not have "\
1860 "GenerateConsoleCtrlEvent(). This may mean that "\
1861 "parts of this process group have NOT been killed.")
1862 except win32api
.error
, ex
:
1863 if ex
.args
[0] not in (6, 87):
1864 # Ignore the following:
1865 # api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
1866 # api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
1867 # Get error 6 if there is no console.
1870 # Last resort: call TerminateProcess if it has not yet.
1873 self
.wait(gracePeriod
)
1874 except ProcessError
, ex
:
1875 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
))
1876 win32process
.TerminateProcess(self
._hProcess
, -1)
1877 win32api
.Sleep(100) # wait for resources to be released
1881 sig
= signal
.SIGKILL
1883 os
.kill(self
._pid
, sig
)
1886 # Ignore: OSError: [Errno 3] No such process
1889 _unregisterProcess(self
)
1891 def _close_(self
, hwnd
, dummy
):
1892 """Callback used by .kill() on Windows.
1894 EnumWindows callback - sends WM_CLOSE to any window owned by this
1897 threadId
, processId
= win32process
.GetWindowThreadProcessId(hwnd
)
1898 if processId
== self
._processId
:
1900 win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0)
1904 """Want to be able to both read and write to this buffer from
1905 difference threads and have the same read/write semantics as for a
1908 This class is subclass-able. _doRead(), _doWrite(), _doReadline(),
1909 _doClose(), _haveLine(), and _haveNumBytes() can be overridden for
1910 specific functionality. The synchronization issues (block on read
1911 until write provides the needed data, termination) are handled for
1915 .seek() # Because we are managing *two* positions (one each
1916 .tell() # for reading and writing), these do not make
1920 # - Is performance a problem? This will likely be slower that
1921 # StringIO.StringIO().
1923 def __init__(self
, mutex
=None, stateChange
=None, name
=None):
1924 """'name' can be set for debugging, it will be used in log messages."""
1925 if name
is not None:
1928 self
._name
= id(self
)
1929 log
.info("[%s] IOBuffer.__init__()" % self
._name
)
1932 # A state change is defined as the buffer being closed or a
1934 if mutex
is not None:
1937 self
._mutex
= threading
.Lock()
1938 if stateChange
is not None:
1939 self
._stateChange
= stateChange
1941 self
._stateChange
= threading
.Condition()
1944 def _doWrite(self
, s
):
1945 self
.__buf
+= s
# Append to buffer.
1948 log
.info("[%s] IOBuffer.write(s=%r)", self
._name
, s
)
1949 # Silently drop writes after the buffer has been close()'d.
1952 # If empty write, close buffer (mimicking behaviour from
1958 self
._mutex
.acquire()
1960 self
._stateChange
.acquire()
1961 self
._stateChange
.notifyAll() # Notify of the write().
1962 self
._stateChange
.release()
1963 self
._mutex
.release()
1965 def writelines(self
, list):
1966 self
.write(''.join(list))
1968 def _doRead(self
, n
):
1969 """Pop 'n' bytes from the internal buffer and return them."""
1971 idx
= len(self
.__buf
)
1973 idx
= min(n
, len(self
.__buf
))
1974 retval
, self
.__buf
= self
.__buf
[:idx
], self
.__buf
[idx
:]
1977 def read(self
, n
=-1):
1978 log
.info("[%s] IOBuffer.read(n=%r)" % (self
._name
, n
))
1979 log
.info("[%s] IOBuffer.read(): wait for data" % self
._name
)
1981 # Wait until the buffer is closed, i.e. no more writes will
1984 if self
._closed
: break
1985 #log.debug("[%s] <<< IOBuffer.read: state change .wait()"\
1987 self
._stateChange
.acquire()
1988 self
._stateChange
.wait()
1989 self
._stateChange
.release()
1990 #log.debug("[%s] >>> IOBuffer.read: done change .wait()"\
1993 # Wait until there are the requested number of bytes to read
1994 # (or until the buffer is closed, i.e. no more writes will
1996 # XXX WARNING: I *think* there is a race condition around
1997 # here whereby self.fparent.read() in _InFileProxy can
1998 # hang. *Sometime* test_stdin::test_stdin_buffer() will
1999 # hang. This was *before* I moved the
2000 # _stateChange.acquire() and .release() calls out side
2001 # of the 'while 1:' here. ...and now they are back
2004 if self
._closed
: break
2005 if self
._haveNumBytes
(n
): break
2006 #log.debug("[%s] <<< IOBuffer.read: state change .wait()"\
2008 self
._stateChange
.acquire()
2009 self
._stateChange
.wait()
2010 self
._stateChange
.release()
2011 #log.debug("[%s] >>> IOBuffer.read: done change .wait()"\
2013 log
.info("[%s] IOBuffer.read(): done waiting for data" % self
._name
)
2015 self
._mutex
.acquire()
2016 retval
= self
._doRead
(n
)
2017 self
._mutex
.release()
2020 def _doReadline(self
, n
):
2021 """Pop the front line (or n bytes of it, whichever is less) from
2022 the internal buffer and return it.
2024 idx
= self
.__buf
.find('\n')
2026 idx
= len(self
.__buf
)
2028 idx
+= 1 # include the '\n'
2031 retval
, self
.__buf
= self
.__buf
[:idx
], self
.__buf
[idx
:]
2034 def _haveLine(self
):
2035 return self
.__buf
.find('\n') != -1
2037 def _haveNumBytes(self
, n
=None):
2038 return len(self
.__buf
) >= n
2040 def readline(self
, n
=None):
2041 # Wait until there is a full line (or at least 'n' bytes)
2042 # in the buffer or until the buffer is closed, i.e. no more
2044 log
.info("[%s] IOBuffer.readline(n=%r)" % (self
._name
, n
))
2046 log
.info("[%s] IOBuffer.readline(): wait for data" % self
._name
)
2048 if self
._closed
: break
2049 if self
._haveLine
(): break
2050 if n
is not None and self
._haveNumBytes
(n
): break
2051 self
._stateChange
.acquire()
2052 self
._stateChange
.wait()
2053 self
._stateChange
.release()
2054 log
.info("[%s] IOBuffer.readline(): done waiting for data"\
2057 self
._mutex
.acquire()
2058 retval
= self
._doReadline
(n
)
2059 self
._mutex
.release()
2062 def readlines(self
):
2065 line
= self
.readline()
2076 if not self
._closed
:
2077 log
.info("[%s] IOBuffer.close()" % self
._name
)
2080 self
._stateChange
.acquire()
2081 self
._stateChange
.notifyAll() # Notify of the close().
2082 self
._stateChange
.release()
2085 log
.info("[%s] IOBuffer.flush()" % self
._name
)
2086 #XXX Perhaps flush() should unwedged possible waiting .read()
2087 # and .readline() calls that are waiting for more data???
2090 class _InFileProxy(threading
.Thread
):
2091 """A thread to proxy stdin.write()'s from the parent to the child."""
2092 def __init__(self
, fParent
, fChild
, name
=None):
2094 "fParent" is a Python file-like object setup for writing.
2095 "fChild" is a Win32 handle to the a child process' output pipe.
2096 "name" can be set for debugging, it will be used in log messages.
2098 log
.info("[%s, %s] _InFileProxy.__init__(fChild=%r, fParent=%r)",
2099 name
, id(self
), fChild
, fParent
)
2100 threading
.Thread
.__init
__(self
, name
=name
)
2101 self
.fChild
= fChild
2102 self
.fParent
= fParent
2105 log
.info("[%s] _InFileProxy: start" % self
.getName())
2107 self
._proxyFromParentToChild
()
2109 log
.info("[%s] _InFileProxy: closing parent (%r)"\
2110 % (self
.getName(), self
.fParent
))
2112 self
.fParent
.close()
2114 pass # Ignore: IOError: [Errno 4] Interrupted system call
2115 log
.info("[%s] _InFileProxy: done" % self
.getName())
2117 def _proxyFromParentToChild(self
):
2119 # Read output from the child process, and (for now) just write
2122 log
.info("[%s] _InFileProxy: waiting for read on parent (%r)"\
2123 % (self
.getName(), self
.fParent
))
2124 # XXX Get hangs here (!) even with
2125 # self.stdin.close() in ProcessProxy' __del__() under this
2127 # p = ProcessProxy([...], stdin=sys.stdin)
2128 # The user must manually send '\n' via <Enter> or EOF
2129 # via <Ctrl-Z> to unlock this. How to get around that?
2130 # See cleanOnTermination note in _OutFileProxy.run()
2132 #log.debug("XXX -> start read on %r" % self.fParent)
2134 text
= self
.fParent
.read(CHUNKSIZE
)
2135 except ValueError, ex
:
2136 # ValueError is raised with trying to write to a closed
2139 #log.debug("XXX <- done read on %r" % self.fParent)
2141 # Empty text signifies that the pipe has been closed on
2143 log
.info("[%s] _InFileProxy: observed close of parent (%r)"\
2144 % (self
.getName(), self
.fParent
))
2145 # Signal the child so it knows to stop listening.
2147 logres
.info("[%s] _InFileProxy: closing child after "\
2148 "observing parent's close: %r", self
.getName(),
2153 pass # Ignore: IOError: [Errno 4] Interrupted system call
2155 # Ignore: IOError: [Errno 9] Bad file descriptor
2156 # XXX Do we *know* we want to do that?
2160 log
.info("[%s] _InFileProxy: read %d bytes from parent: %r"\
2161 % (self
.getName(), len(text
), text
))
2163 log
.info("[%s, %s] _InFileProxy: writing %r to child (%r)",
2164 self
.getName(), id(self
), text
, self
.fChild
)
2166 self
.fChild
.write(text
)
2167 except (OSError, IOError), ex
:
2168 # Ignore errors for now. For example:
2169 # - Get this on Win9x when writing multiple lines to "dir":
2170 # OSError: [Errno 32] Broken pipe
2171 #XXX There *may* be errors we don't want to avoid.
2172 #XXX Should maybe just ignore EnvironmentError (base class).
2173 log
.info("[%s] _InFileProxy: error writing to child (%r), "\
2174 "closing: %s" % (self
.getName(), self
.fParent
, ex
))
2176 log
.info("[%s] _InFileProxy: wrote %d bytes to child: %r"\
2177 % (self
.getName(), len(text
), text
))
2180 class _OutFileProxy(threading
.Thread
):
2181 """A thread to watch an "out" file from the spawned child process
2182 and pass on write's to the parent.
2184 def __init__(self
, fChild
, fParent
, toClose
=[], name
=None):
2186 "fChild" is a Win32 handle to the a child process' output pipe.
2187 "fParent" is a Python file-like object setup for writing.
2188 "toClose" is a list of objects on which to call .close when this
2189 proxy is terminating.
2190 "name" can be set for debugging, it will be used in log messages.
2192 log
.info("[%s] _OutFileProxy.__init__(fChild=%r, fParent=%r, "\
2193 "toClose=%r)", name
, fChild
, fParent
, toClose
)
2194 threading
.Thread
.__init
__(self
, name
=name
)
2195 self
.fChild
= fChild
2196 self
.fParent
= fParent
2197 self
.toClose
= toClose
2200 log
.info("[%s] _OutFileProxy: start" % self
.getName())
2202 self
._proxyFromChildToParent
()
2204 logres
.info("[%s] _OutFileProxy: terminating, close child (%r)",
2205 self
.getName(), self
.fChild
)
2209 pass # Ignore: IOError: [Errno 4] Interrupted system call
2210 log
.info("[%s] _OutFileProxy: closing parent (%r)",
2211 self
.getName(), self
.fParent
)
2213 self
.fParent
.close()
2215 pass # Ignore: IOError: [Errno 4] Interrupted system call
2217 logres
.info("[%s] _OutFileProxy: closing %r after "\
2218 "closing parent", self
.getName(), self
.toClose
[0])
2220 self
.toClose
[0].close()
2222 pass # Ignore: IOError: [Errno 4] Interrupted system call
2224 log
.info("[%s] _OutFileProxy: done" % self
.getName())
2226 def _proxyFromChildToParent(self
):
2228 # Read output from the child process, and (for now) just write
2233 log
.info("[%s] _OutFileProxy: waiting for read on child (%r)"\
2234 % (self
.getName(), self
.fChild
))
2235 text
= self
.fChild
.read(CHUNKSIZE
)
2237 # Ignore: IOError: [Errno 9] Bad file descriptor
2238 # XXX Do we *know* we want to do that?
2239 log
.info("[%s] _OutFileProxy: error reading from child (%r), "\
2240 "shutting down: %s", self
.getName(), self
.fChild
, ex
)
2243 # Empty text signifies that the pipe has been closed on
2245 log
.info("[%s] _OutFileProxy: observed close of child (%r)"\
2246 % (self
.getName(), self
.fChild
))
2249 log
.info("[%s] _OutFileProxy: text(len=%d): %r",
2250 self
.getName(), len(text
), text
)
2251 self
.fParent
.write(text
)
2255 if sys
.platform
.startswith("linux"):
2257 """Mixin class for various classes in the Process hierarchy to
2258 work around the known LinuxThreads bug where one cannot .wait()
2259 on a created process from a subthread of the thread that created
2263 class ProcessXXX(_ThreadFixer, BrokenProcessXXX):
2264 _pclass = BrokenProcessXXX
2267 Because we must do all real os.wait() calls on the child
2268 process from the thread that spawned it, we use a proxy
2269 thread whose only responsibility is just that. The proxy
2270 thread just starts the child and then immediately wait's for
2271 the child to terminate. On termination is stores the exit
2272 status (for use by the main thread) and notifies any thread
2273 waiting for this termination (possibly the main thread). The
2274 overriden .wait() uses this stored exit status and the
2275 termination notification to simulate the .wait().
2277 def __init__(self
, *args
, **kwargs
):
2278 # Keep a reference to 'log' ensure it is around for this object's
2281 self
.__waiter
= None
2282 self
.__hasTerminated
= threading
.Condition()
2283 self
.__terminationResult
= None
2284 self
.__childStarted
= threading
.Condition()
2285 self
._pclass
.__init
__(self
, *args
, **kwargs
)
2287 def _forkAndExecChildOnUnix(self
, *args
, **kwargs
):
2288 """Fork and start the child process do it in a special subthread
2289 that will negotiate subsequent .wait()'s.
2291 Sets self._pid as a side effect.
2293 self
.__waiter
= threading
.Thread(
2294 target
=self
.__launchAndWait
, args
=args
, kwargs
=kwargs
)
2296 # Start subthread that will launch child and wait until it
2298 self
.__childStarted
.acquire()
2299 self
.__waiter
.start()
2300 self
.__childStarted
.wait()
2301 self
.__childStarted
.release()
2303 def __launchAndWait(self
, *args
, **kwargs
):
2304 """Launch the given command and wait for it to terminate.
2306 When the process has terminated then store its exit value
2309 logfix
.info("start child in thread %s",
2310 threading
.currentThread().getName())
2312 # Spawn the child process and notify the main thread of
2314 self
.__childStarted
.acquire()
2315 self
._pclass
._forkAndExecChildOnUnix
(self
, *args
, **kwargs
)
2316 self
.__childStarted
.notifyAll()
2317 self
.__childStarted
.release()
2319 # Wait on the thread and store appropriate results when
2322 waitResult
= self
._pclass
.wait(self
)
2323 except ProcessError
, ex
:
2325 self
.__hasTerminated
.acquire()
2326 self
.__terminationResult
= waitResult
2327 self
.__hasTerminated
.notifyAll()
2328 self
.__hasTerminated
.release()
2330 self
.__waiter
= None # drop ref that would keep instance alive
2332 def wait(self
, timeout
=None):
2333 # If the process __hasTerminated then return the exit
2334 # status. Otherwise simulate the wait as appropriate.
2336 # - This class is only used on linux so 'timeout' has the
2337 # Unix 'timeout' semantics.
2338 self
.__hasTerminated
.acquire()
2339 if self
.__terminationResult
is None:
2340 if timeout
== os
.WNOHANG
: # Poll.
2341 self
.__hasTerminated
.wait(0)
2342 else: # Block until process finishes.
2343 self
.__hasTerminated
.wait()
2344 terminationResult
= self
.__terminationResult
2345 self
.__hasTerminated
.release()
2347 if terminationResult
is None:
2348 # process has not finished yet
2349 raise ProcessError("Wait for process timed out.",
2351 elif isinstance(terminationResult
, Exception):
2352 # some error waiting for process termination
2353 raise terminationResult
2355 # the process terminated
2356 return terminationResult
2358 _ThreadBrokenProcess
= Process
2359 class Process(_ThreadFixer
, _ThreadBrokenProcess
):
2360 _pclass
= _ThreadBrokenProcess
2362 _ThreadBrokenProcessOpen
= ProcessOpen
2363 class ProcessOpen(_ThreadFixer
, _ThreadBrokenProcessOpen
):
2364 _pclass
= _ThreadBrokenProcessOpen
2366 _ThreadBrokenProcessProxy
= ProcessProxy
2367 class ProcessProxy(_ThreadFixer
, _ThreadBrokenProcessProxy
):
2368 _pclass
= _ThreadBrokenProcessProxy