startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = _winapi.SW_HIDE
comspec = os.environ.get("COMSPEC", "cmd.exe")
args = '{} /c "{}"'.format (comspec, args)
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
os.fspath(cwd) if cwd is not None else None,
# Child is launched. Close the parent's copy of those pipe
# handles that only the child should have open. You need
# to make sure that no handles to the write end of the
# output pipe are maintained in this process or else the
# pipe will not close when the child process exits and the
if hasattr(self, '_devnull'):
# Prevent a double close of these handles/fds from __init__
self._closed_child_pipe_fds = True
# Retain the process handle, but close the thread handle
self._child_created = True
self._handle = Handle(hp)
def _internal_poll(self, _deadstate=None,
_WaitForSingleObject=_winapi.WaitForSingleObject,
_WAIT_OBJECT_0=_winapi.WAIT_OBJECT_0,
_GetExitCodeProcess=_winapi.GetExitCodeProcess):
"""Check if child process has terminated. Returns returncode
This method is called by __del__, so it can only refer to objects
if self.returncode is None:
if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0:
self.returncode = _GetExitCodeProcess(self._handle)
def wait(self, timeout=None, endtime=None):
"""Wait for child process to terminate. Returns returncode
"'endtime' argument is deprecated; use 'timeout'.",
timeout = self._remaining_time(endtime)
timeout_millis = _winapi.INFINITE
timeout_millis = int(timeout * 1000)
if self.returncode is None:
result = _winapi.WaitForSingleObject(self._handle,
if result == _winapi.WAIT_TIMEOUT:
raise TimeoutExpired(self.args, timeout)
self.returncode = _winapi.GetExitCodeProcess(self._handle)
def _readerthread(self, fh, buffer):
def _communicate(self, input, endtime, orig_timeout):
# Start reader threads feeding into a list hanging off of this
# object, unless they've already been started.
if self.stdout and not hasattr(self, "_stdout_buff"):
threading.Thread(target=self._readerthread,
args=(self.stdout, self._stdout_buff))
self.stdout_thread.daemon = True
self.stdout_thread.start()
if self.stderr and not hasattr(self, "_stderr_buff"):
threading.Thread(target=self._readerthread,
args=(self.stderr, self._stderr_buff))
self.stderr_thread.daemon = True
self.stderr_thread.start()
# Wait for the reader threads, or time out. If we time out, the
# threads remain reading and the fds left open in case the user
# calls communicate again.
if self.stdout is not None:
self.stdout_thread.join(self._remaining_time(endtime))
if self.stdout_thread.is_alive():
raise TimeoutExpired(self.args, orig_timeout)
if self.stderr is not None:
self.stderr_thread.join(self._remaining_time(endtime))
if self.stderr_thread.is_alive():
raise TimeoutExpired(self.args, orig_timeout)
# Collect the output from and close both pipes, now that we know
# both have been read successfully.
stdout = self._stdout_buff
stderr = self._stderr_buff
# All data exchanged. Translate lists into strings.
def send_signal(self, sig):
"""Send a signal to the process."""
# Don't signal a process that we know has already died.
if self.returncode is not None:
if sig == signal.SIGTERM:
elif sig == signal.CTRL_C_EVENT:
os.kill(self.pid, signal.CTRL_C_EVENT)
elif sig == signal.CTRL_BREAK_EVENT:
os.kill(self.pid, signal.CTRL_BREAK_EVENT)
raise ValueError("Unsupported signal: {}".format(sig))
"""Terminates the process."""
# Don't terminate a process that we know has already died.
if self.returncode is not None:
_winapi.TerminateProcess(self._handle, 1)
# ERROR_ACCESS_DENIED (winerror 5) is received when the
rc = _winapi.GetExitCodeProcess(self._handle)
if rc == _winapi.STILL_ACTIVE:
def _get_handles(self, stdin, stdout, stderr):
"""Construct and return tuple with IO objects:
p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
p2cread, p2cwrite = -1, -1
c2pread, c2pwrite = -1, -1
errread, errwrite = -1, -1
p2cread, p2cwrite = os.pipe()
p2cread = self._get_devnull()
elif isinstance(stdin, int):
# Assuming file-like object
c2pread, c2pwrite = os.pipe()
c2pwrite = self._get_devnull()
elif isinstance(stdout, int):
# Assuming file-like object
c2pwrite = stdout.fileno()
errread, errwrite = os.pipe()
else: # child's stdout is not set, use parent's stdout
errwrite = sys.__stdout__.fileno()
errwrite = self._get_devnull()
elif isinstance(stderr, int):
# Assuming file-like object
errwrite = stderr.fileno()
return (p2cread, p2cwrite,
def _execute_child(self, args, executable, preexec_fn, close_fds,
startupinfo, creationflags, shell,
restore_signals, start_new_session):
"""Execute program (POSIX version)"""
if isinstance(args, (str, bytes)):
args = ["/bin/sh", "-c"] + args
orig_executable = executable
# For transferring possible exec failure from child to parent.
# Data format: "exception name:hex errno:description"
# Pickle is not used; it is complex and involves memory allocation.
errpipe_read, errpipe_write = os.pipe()
# errpipe_write must not be in the standard io 0, 1, or 2 fd range.
low_fds_to_close.append(errpipe_write)
errpipe_write = os.dup(errpipe_write)
for low_fd in low_fds_to_close:
# We must avoid complex work that could involve
# malloc or free in the child process to avoid
# potential deadlocks, thus we do all this here.
# and pass it to fork_exec()
raise ValueError("illegal environment variable name")
env_list.append(k + b'=' + os.fsencode(v))
env_list = None # Use execv instead of execve.
executable = os.fsencode(executable)
if os.path.dirname(executable):
executable_list = (executable,)
# This matches the behavior of os._execvpe().
os.path.join(os.fsencode(dir), executable)
for dir in os.get_exec_path(env))
fds_to_keep = set(pass_fds)
fds_to_keep.add(errpipe_write)
self.pid = _posixsubprocess.fork_exec(
close_fds, tuple(sorted(map(int, fds_to_keep))),
p2cread, p2cwrite, c2pread, c2pwrite,
errpipe_read, errpipe_write,
restore_signals, start_new_session, preexec_fn)
self._child_created = True
# be sure the FD is closed no matter what
# self._devnull is not always defined.
devnull_fd = getattr(self, '_devnull', None)
if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
if devnull_fd is not None:
# Prevent a double close of these fds from __init__ on error.
self._closed_child_pipe_fds = True
# Wait for exec to fail or succeed; possibly raising an
# exception (limited in size)
errpipe_data = bytearray()
part = os.read(errpipe_read, 50000)
if not part or len(errpipe_data) > 50000:
# be sure the FD is closed no matter what
pid, sts = os.waitpid(self.pid, 0)
self._handle_exitstatus(sts)
self.returncode = sys.maxsize
except ChildProcessError:
exception_name, hex_errno, err_msg = (
errpipe_data.split(b':', 2))
# The encoding here should match the encoding
# written in by the subprocess implementations
err_msg = err_msg.decode()
exception_name = b'SubprocessError'
err_msg = 'Bad exception data from child: {!r}'.format(
child_exception_type = getattr(
builtins, exception_name.decode('ascii'),
if issubclass(child_exception_type, OSError) and hex_errno:
errno_num = int(hex_errno, 16)
child_exec_never_called = (err_msg == "noexec")
if child_exec_never_called:
# The error must be from chdir(cwd).
err_filename = orig_executable
err_msg = os.strerror(errno_num)
if errno_num == errno.ENOENT:
err_msg += ': ' + repr(err_filename)
raise child_exception_type(errno_num, err_msg, err_filename)
raise child_exception_type(err_msg)
def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED,
_WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED,
_WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED,
"""All callers to this function MUST hold self._waitpid_lock."""
# This method is called (indirectly) by __del__, so it cannot
# refer to anything outside of its local scope.
self.returncode = -_WTERMSIG(sts)
self.returncode = _WEXITSTATUS(sts)
self.returncode = -_WSTOPSIG(sts)
raise SubprocessError("Unknown child exit status!")
def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,
_WNOHANG=os.WNOHANG, _ECHILD=errno.ECHILD):
"""Check if child process has terminated. Returns returncode
This method is called by __del__, so it cannot reference anything
outside of the local scope (nor can any methods it calls).
if self.returncode is None:
if not self._waitpid_lock.acquire(False):
# Something else is busy calling waitpid. Don't allow two
# at once. We know nothing yet.
if self.returncode is not None:
return self.returncode # Another thread waited.
pid, sts = _waitpid(self.pid, _WNOHANG)
self._handle_exitstatus(sts)
if _deadstate is not None:
self.returncode = _deadstate
# This happens if SIGCLD is set to be ignored or
# waiting for child processes has otherwise been
# disabled for our process. This child is dead, we
# http://bugs.python.org/issue15756
self._waitpid_lock.release()
def _try_wait(self, wait_flags):
"""All callers to this function MUST hold self._waitpid_lock."""
(pid, sts) = os.waitpid(self.pid, wait_flags)
except ChildProcessError:
# This happens if SIGCLD is set to be ignored or waiting
# for child processes has otherwise been disabled for our
# process. This child is dead, we can't get the status.
def wait(self, timeout=None, endtime=None):
"""Wait for child process to terminate. Returns returncode
if self.returncode is not None:
"'endtime' argument is deprecated; use 'timeout'.",
if endtime is not None or timeout is not None:
endtime = _time() + timeout
timeout = self._remaining_time(endtime)
# Enter a busy loop if we have a timeout. This busy loop was
# cribbed from Lib/threading.py in Thread.wait() at r71065.
delay = 0.0005 # 500 us -> initial delay of 1 ms
if self._waitpid_lock.acquire(False):
if self.returncode is not None:
break # Another thread waited.
(pid, sts) = self._try_wait(os.WNOHANG)
assert pid == self.pid or pid == 0
self._handle_exitstatus(sts)
self._waitpid_lock.release()
remaining = self._remaining_time(endtime)
raise TimeoutExpired(self.args, timeout)
delay = min(delay * 2, remaining, .05)
while self.returncode is None:
if self.returncode is not None:
break # Another thread waited.
(pid, sts) = self._try_wait(0)
# Check the pid and loop as waitpid has been known to
# return 0 even without WNOHANG in odd situations.
# http://bugs.python.org/issue14396.
self._handle_exitstatus(sts)
def _communicate(self, input, endtime, orig_timeout):
if self.stdin and not self._communication_started:
# Flush stdio buffer. This might block, if the user has
# been writing to .stdin in an uncontrolled fashion.
pass # communicate() must ignore BrokenPipeError.
pass # communicate() must ignore BrokenPipeError.