1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
"""
Support routines for subprocess module.
Currently, this extension module is only required when using the
subprocess module on Windows.
"""
import sys
if sys.platform != 'win32':
raise ImportError("The '_subprocess' module is only available on Windows")
# Declare external Win32 functions
from _pypy_winbase_cffi import ffi as _ffi
_kernel32 = _ffi.dlopen('kernel32')
GetVersion = _kernel32.GetVersion
# Now the _subprocess module implementation
def _WinError():
code, message = _ffi.getwinerror()
raise WindowsError(code, message)
def _int2handle(val):
return _ffi.cast("HANDLE", val)
_INVALID_HANDLE_VALUE = _int2handle(-1)
class _handle(object):
def __init__(self, c_handle):
# 'c_handle' is a cffi cdata of type HANDLE, which is basically 'void *'
self.c_handle = c_handle
if int(self) != -1:
self.c_handle = _ffi.gc(self.c_handle, _kernel32.CloseHandle)
def __int__(self):
return int(_ffi.cast("intptr_t", self.c_handle))
def __repr__(self):
return '<_subprocess.handle %d at 0x%x>' % (int(self), id(self))
def Detach(self):
h = int(self)
if h != -1:
c_handle = self.c_handle
self.c_handle = _INVALID_HANDLE_VALUE
_ffi.gc(c_handle, None)
return h
def Close(self):
if int(self) != -1:
c_handle = self.c_handle
self.c_handle = _INVALID_HANDLE_VALUE
_ffi.gc(c_handle, None)
_kernel32.CloseHandle(c_handle)
def CreatePipe(attributes, size):
handles = _ffi.new("HANDLE[2]")
res = _kernel32.CreatePipe(handles, handles + 1, _ffi.NULL, size)
if not res:
raise _WinError()
return _handle(handles[0]), _handle(handles[1])
def GetCurrentProcess():
return _handle(_kernel32.GetCurrentProcess())
def DuplicateHandle(source_process, source, target_process, access, inherit, options=0):
# CPython: the first three arguments are expected to be integers
target = _ffi.new("HANDLE[1]")
res = _kernel32.DuplicateHandle(
_int2handle(source_process),
_int2handle(source),
_int2handle(target_process),
target, access, inherit, options)
if not res:
raise _WinError()
return _handle(target[0])
def _z(input):
if input is None:
return _ffi.NULL
if isinstance(input, basestring):
return str(input)
raise TypeError("string/unicode/None expected, got %r" % (
type(input).__name__,))
def CreateProcess(name, command_line, process_attr, thread_attr,
inherit, flags, env, start_dir, startup_info):
si = _ffi.new("STARTUPINFO *")
if startup_info is not None:
si.dwFlags = startup_info.dwFlags
si.wShowWindow = startup_info.wShowWindow
# CPython: these three handles are expected to be _handle objects
if startup_info.hStdInput:
si.hStdInput = startup_info.hStdInput.c_handle
if startup_info.hStdOutput:
si.hStdOutput = startup_info.hStdOutput.c_handle
if startup_info.hStdError:
si.hStdError = startup_info.hStdError.c_handle
pi = _ffi.new("PROCESS_INFORMATION *")
if env is not None:
envbuf = ""
for k, v in env.iteritems():
envbuf += "%s=%s\0" % (k, v)
envbuf += '\0'
else:
envbuf = _ffi.NULL
res = _kernel32.CreateProcessA(_z(name), _z(command_line), _ffi.NULL,
_ffi.NULL, inherit, flags, envbuf,
_z(start_dir), si, pi)
if not res:
raise _WinError()
return (_handle(pi.hProcess),
_handle(pi.hThread),
pi.dwProcessId,
pi.dwThreadId)
def WaitForSingleObject(handle, milliseconds):
# CPython: the first argument is expected to be an integer.
res = _kernel32.WaitForSingleObject(_int2handle(handle), milliseconds)
if res < 0:
raise _WinError()
return res
def GetExitCodeProcess(handle):
# CPython: the first argument is expected to be an integer.
code = _ffi.new("DWORD[1]")
res = _kernel32.GetExitCodeProcess(_int2handle(handle), code)
if not res:
raise _WinError()
return code[0]
def TerminateProcess(handle, exitcode):
# CPython: the first argument is expected to be an integer.
# The second argument is silently wrapped in a UINT.
res = _kernel32.TerminateProcess(_int2handle(handle),
_ffi.cast("UINT", exitcode))
if not res:
raise _WinError()
def GetStdHandle(stdhandle):
stdhandle = _ffi.cast("DWORD", stdhandle)
res = _kernel32.GetStdHandle(stdhandle)
if not res:
return None
else:
# note: returns integer, not handle object
return int(_ffi.cast("intptr_t", res))
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
DUPLICATE_SAME_ACCESS = 2
STARTF_USESTDHANDLES = 0x100
STARTF_USESHOWWINDOW = 0x001
SW_HIDE = 0
INFINITE = 0xffffffff
WAIT_OBJECT_0 = 0
CREATE_NEW_CONSOLE = 0x010
CREATE_NEW_PROCESS_GROUP = 0x200
STILL_ACTIVE = 259
|