diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 90c1ea7abf5..3a61e5ee42a 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -51,12 +51,12 @@ from multiprocessing import current_process, AuthenticationError, BufferTooShort from multiprocessing.util import ( get_temp_dir, Finalize, sub_debug, debug, _eintr_retry) try: - from _multiprocessing import win32 - from _subprocess import WAIT_OBJECT_0, WAIT_TIMEOUT, INFINITE + import _winapi + from _winapi import WAIT_OBJECT_0, WAIT_TIMEOUT, INFINITE except ImportError: if sys.platform == 'win32': raise - win32 = None + _winapi = None # # @@ -282,7 +282,7 @@ class _ConnectionBase: return self._poll(timeout) -if win32: +if _winapi: class PipeConnection(_ConnectionBase): """ @@ -292,14 +292,14 @@ if win32: """ _got_empty_message = False - def _close(self, _CloseHandle=win32.CloseHandle): + def _close(self, _CloseHandle=_winapi.CloseHandle): _CloseHandle(self._handle) def _send_bytes(self, buf): - ov, err = win32.WriteFile(self._handle, buf, overlapped=True) + ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True) try: - if err == win32.ERROR_IO_PENDING: - waitres = win32.WaitForMultipleObjects( + if err == _winapi.ERROR_IO_PENDING: + waitres = _winapi.WaitForMultipleObjects( [ov.event], False, INFINITE) assert waitres == WAIT_OBJECT_0 except: @@ -317,11 +317,11 @@ if win32: else: bsize = 128 if maxsize is None else min(maxsize, 128) try: - ov, err = win32.ReadFile(self._handle, bsize, - overlapped=True) + ov, err = _winapi.ReadFile(self._handle, bsize, + overlapped=True) try: - if err == win32.ERROR_IO_PENDING: - waitres = win32.WaitForMultipleObjects( + if err == _winapi.ERROR_IO_PENDING: + waitres = _winapi.WaitForMultipleObjects( [ov.event], False, INFINITE) assert waitres == WAIT_OBJECT_0 except: @@ -333,10 +333,10 @@ if win32: f = io.BytesIO() f.write(ov.getbuffer()) return f - elif err == win32.ERROR_MORE_DATA: + elif err == _winapi.ERROR_MORE_DATA: return self._get_more_data(ov, maxsize) except IOError as e: - if e.winerror == win32.ERROR_BROKEN_PIPE: + if e.winerror == _winapi.ERROR_BROKEN_PIPE: raise EOFError else: raise @@ -344,7 +344,7 @@ if win32: def _poll(self, timeout): if (self._got_empty_message or - win32.PeekNamedPipe(self._handle)[0] != 0): + _winapi.PeekNamedPipe(self._handle)[0] != 0): return True if timeout < 0: timeout = None @@ -354,11 +354,11 @@ if win32: buf = ov.getbuffer() f = io.BytesIO() f.write(buf) - left = win32.PeekNamedPipe(self._handle)[1] + left = _winapi.PeekNamedPipe(self._handle)[1] assert left > 0 if maxsize is not None and len(buf) + left > maxsize: self._bad_message_length() - ov, err = win32.ReadFile(self._handle, left, overlapped=True) + ov, err = _winapi.ReadFile(self._handle, left, overlapped=True) rbytes, err = ov.GetOverlappedResult(True) assert err == 0 assert rbytes == left @@ -372,11 +372,11 @@ class Connection(_ConnectionBase): a socket handle (Windows). """ - if win32: - def _close(self, _close=win32.closesocket): + if _winapi: + def _close(self, _close=_multiprocessing.closesocket): _close(self._handle) - _write = win32.send - _read = win32.recv + _write = _multiprocessing.send + _read = _multiprocessing.recv else: def _close(self, _close=os.close): _close(self._handle) @@ -526,30 +526,30 @@ else: ''' address = arbitrary_address('AF_PIPE') if duplex: - openmode = win32.PIPE_ACCESS_DUPLEX - access = win32.GENERIC_READ | win32.GENERIC_WRITE + openmode = _winapi.PIPE_ACCESS_DUPLEX + access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE obsize, ibsize = BUFSIZE, BUFSIZE else: - openmode = win32.PIPE_ACCESS_INBOUND - access = win32.GENERIC_WRITE + openmode = _winapi.PIPE_ACCESS_INBOUND + access = _winapi.GENERIC_WRITE obsize, ibsize = 0, BUFSIZE - h1 = win32.CreateNamedPipe( - address, openmode | win32.FILE_FLAG_OVERLAPPED | - win32.FILE_FLAG_FIRST_PIPE_INSTANCE, - win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | - win32.PIPE_WAIT, - 1, obsize, ibsize, win32.NMPWAIT_WAIT_FOREVER, win32.NULL + h1 = _winapi.CreateNamedPipe( + address, openmode | _winapi.FILE_FLAG_OVERLAPPED | + _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE, + _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | + _winapi.PIPE_WAIT, + 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL ) - h2 = win32.CreateFile( - address, access, 0, win32.NULL, win32.OPEN_EXISTING, - win32.FILE_FLAG_OVERLAPPED, win32.NULL + h2 = _winapi.CreateFile( + address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING, + _winapi.FILE_FLAG_OVERLAPPED, _winapi.NULL ) - win32.SetNamedPipeHandleState( - h2, win32.PIPE_READMODE_MESSAGE, None, None + _winapi.SetNamedPipeHandleState( + h2, _winapi.PIPE_READMODE_MESSAGE, None, None ) - overlapped = win32.ConnectNamedPipe(h1, overlapped=True) + overlapped = _winapi.ConnectNamedPipe(h1, overlapped=True) _, err = overlapped.GetOverlappedResult(True) assert err == 0 @@ -630,26 +630,26 @@ if sys.platform == 'win32': ) def _new_handle(self, first=False): - flags = win32.PIPE_ACCESS_DUPLEX | win32.FILE_FLAG_OVERLAPPED + flags = _winapi.PIPE_ACCESS_DUPLEX | _winapi.FILE_FLAG_OVERLAPPED if first: - flags |= win32.FILE_FLAG_FIRST_PIPE_INSTANCE - return win32.CreateNamedPipe( + flags |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE + return _winapi.CreateNamedPipe( self._address, flags, - win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | - win32.PIPE_WAIT, - win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, - win32.NMPWAIT_WAIT_FOREVER, win32.NULL + _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | + _winapi.PIPE_WAIT, + _winapi.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, + _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL ) def accept(self): self._handle_queue.append(self._new_handle()) handle = self._handle_queue.pop(0) - ov = win32.ConnectNamedPipe(handle, overlapped=True) + ov = _winapi.ConnectNamedPipe(handle, overlapped=True) try: - res = win32.WaitForMultipleObjects([ov.event], False, INFINITE) + res = _winapi.WaitForMultipleObjects([ov.event], False, INFINITE) except: ov.cancel() - win32.CloseHandle(handle) + _winapi.CloseHandle(handle) raise finally: _, err = ov.GetOverlappedResult(True) @@ -660,7 +660,7 @@ if sys.platform == 'win32': def _finalize_pipe_listener(queue, address): sub_debug('closing listener with address=%r', address) for handle in queue: - win32.CloseHandle(handle) + _winapi.CloseHandle(handle) def PipeClient(address): ''' @@ -669,23 +669,23 @@ if sys.platform == 'win32': t = _init_timeout() while 1: try: - win32.WaitNamedPipe(address, 1000) - h = win32.CreateFile( - address, win32.GENERIC_READ | win32.GENERIC_WRITE, - 0, win32.NULL, win32.OPEN_EXISTING, - win32.FILE_FLAG_OVERLAPPED, win32.NULL + _winapi.WaitNamedPipe(address, 1000) + h = _winapi.CreateFile( + address, _winapi.GENERIC_READ | _winapi.GENERIC_WRITE, + 0, _winapi.NULL, _winapi.OPEN_EXISTING, + _winapi.FILE_FLAG_OVERLAPPED, _winapi.NULL ) except WindowsError as e: - if e.winerror not in (win32.ERROR_SEM_TIMEOUT, - win32.ERROR_PIPE_BUSY) or _check_timeout(t): + if e.winerror not in (_winapi.ERROR_SEM_TIMEOUT, + _winapi.ERROR_PIPE_BUSY) or _check_timeout(t): raise else: break else: raise - win32.SetNamedPipeHandleState( - h, win32.PIPE_READMODE_MESSAGE, None, None + _winapi.SetNamedPipeHandleState( + h, _winapi.PIPE_READMODE_MESSAGE, None, None ) return PipeConnection(h) @@ -774,7 +774,7 @@ if sys.platform == 'win32': L = list(handles) ready = [] while L: - res = win32.WaitForMultipleObjects(L, False, timeout) + res = _winapi.WaitForMultipleObjects(L, False, timeout) if res == WAIT_TIMEOUT: break elif WAIT_OBJECT_0 <= res < WAIT_OBJECT_0 + len(L): @@ -788,7 +788,7 @@ if sys.platform == 'win32': timeout = 0 return ready - _ready_errors = {win32.ERROR_BROKEN_PIPE, win32.ERROR_NETNAME_DELETED} + _ready_errors = {_winapi.ERROR_BROKEN_PIPE, _winapi.ERROR_NETNAME_DELETED} def wait(object_list, timeout=None): ''' @@ -818,12 +818,12 @@ if sys.platform == 'win32': else: # start an overlapped read of length zero try: - ov, err = win32.ReadFile(fileno(), 0, True) + ov, err = _winapi.ReadFile(fileno(), 0, True) except OSError as e: err = e.winerror if err not in _ready_errors: raise - if err == win32.ERROR_IO_PENDING: + if err == _winapi.ERROR_IO_PENDING: ov_list.append(ov) waithandle_to_obj[ov.event] = o else: @@ -847,7 +847,7 @@ if sys.platform == 'win32': err = e.winerror if err not in _ready_errors: raise - if err != win32.ERROR_OPERATION_ABORTED: + if err != _winapi.ERROR_OPERATION_ABORTED: o = waithandle_to_obj[ov.event] ready_objects.add(o) if err == 0: diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py index 020508a1181..0cbb741cd25 100644 --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -181,10 +181,9 @@ if sys.platform != 'win32': else: import _thread import msvcrt - import _subprocess + import _winapi from pickle import load, HIGHEST_PROTOCOL - from _multiprocessing import win32 def dump(obj, file, protocol=None): ForkingPickler(file, protocol).dump(obj) @@ -197,8 +196,8 @@ else: WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") - exit = win32.ExitProcess - close = win32.CloseHandle + exit = _winapi.ExitProcess + close = _winapi.CloseHandle # # _python_exe is the assumed path to the python executable. @@ -220,11 +219,11 @@ else: def duplicate(handle, target_process=None, inheritable=False): if target_process is None: - target_process = _subprocess.GetCurrentProcess() - return _subprocess.DuplicateHandle( - _subprocess.GetCurrentProcess(), handle, target_process, - 0, inheritable, _subprocess.DUPLICATE_SAME_ACCESS - ).Detach() + target_process = _winapi.GetCurrentProcess() + return _winapi.DuplicateHandle( + _winapi.GetCurrentProcess(), handle, target_process, + 0, inheritable, _winapi.DUPLICATE_SAME_ACCESS + ) # # We define a Popen class similar to the one from subprocess, but @@ -248,10 +247,10 @@ else: # start process cmd = get_command_line() + [rhandle] cmd = ' '.join('"%s"' % x for x in cmd) - hp, ht, pid, tid = _subprocess.CreateProcess( + hp, ht, pid, tid = _winapi.CreateProcess( _python_exe, cmd, None, None, 1, 0, None, None, None ) - ht.Close() + _winapi.CloseHandle(ht) close(rhandle) # set attributes of self @@ -282,13 +281,13 @@ else: def wait(self, timeout=None): if self.returncode is None: if timeout is None: - msecs = _subprocess.INFINITE + msecs = _winapi.INFINITE else: msecs = max(0, int(timeout * 1000 + 0.5)) - res = _subprocess.WaitForSingleObject(int(self._handle), msecs) - if res == _subprocess.WAIT_OBJECT_0: - code = _subprocess.GetExitCodeProcess(self._handle) + res = _winapi.WaitForSingleObject(int(self._handle), msecs) + if res == _winapi.WAIT_OBJECT_0: + code = _winapi.GetExitCodeProcess(self._handle) if code == TERMINATE: code = -signal.SIGTERM self.returncode = code @@ -301,7 +300,7 @@ else: def terminate(self): if self.returncode is None: try: - _subprocess.TerminateProcess(int(self._handle), TERMINATE) + _winapi.TerminateProcess(int(self._handle), TERMINATE) except WindowsError: if self.wait(timeout=0.1) is None: raise diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py index 7366bd2b8b3..7e19434b68a 100644 --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -51,7 +51,7 @@ __all__ = ['BufferWrapper'] if sys.platform == 'win32': - from _multiprocessing import win32 + import _winapi class Arena(object): @@ -61,7 +61,7 @@ if sys.platform == 'win32': self.size = size self.name = 'pym-%d-%d' % (os.getpid(), next(Arena._counter)) self.buffer = mmap.mmap(-1, self.size, tagname=self.name) - assert win32.GetLastError() == 0, 'tagname already in use' + assert _winapi.GetLastError() == 0, 'tagname already in use' self._state = (self.size, self.name) def __getstate__(self): @@ -71,7 +71,7 @@ if sys.platform == 'win32': def __setstate__(self, state): self.size, self.name = self._state = state self.buffer = mmap.mmap(-1, self.size, tagname=self.name) - assert win32.GetLastError() == win32.ERROR_ALREADY_EXISTS + assert _winapi.GetLastError() == _winapi.ERROR_ALREADY_EXISTS else: diff --git a/Lib/multiprocessing/reduction.py b/Lib/multiprocessing/reduction.py index dda4a4120b4..c80de5948a6 100644 --- a/Lib/multiprocessing/reduction.py +++ b/Lib/multiprocessing/reduction.py @@ -60,11 +60,11 @@ if not(sys.platform == 'win32' or (hasattr(socket, 'CMSG_LEN') and # if sys.platform == 'win32': - from _multiprocessing import win32 + import _winapi def send_handle(conn, handle, destination_pid): - process_handle = win32.OpenProcess( - win32.PROCESS_ALL_ACCESS, False, destination_pid + process_handle = _winapi.OpenProcess( + _winapi.PROCESS_ALL_ACCESS, False, destination_pid ) try: new_handle = duplicate(handle, process_handle) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 684086bb5c0..410ae2918b8 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -385,7 +385,7 @@ class TimeoutExpired(SubprocessError): if mswindows: import threading import msvcrt - import _subprocess + import _winapi class STARTUPINFO: dwFlags = 0 hStdInput = None @@ -410,15 +410,36 @@ __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", "getoutput", "check_output", "CalledProcessError", "DEVNULL"] if mswindows: - from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, - STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, - STD_ERROR_HANDLE, SW_HIDE, - STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + from _winapi import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", "STD_ERROR_HANDLE", "SW_HIDE", "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) + + class Handle(int): + closed = False + + def Close(self, CloseHandle=_winapi.CloseHandle): + if not self.closed: + self.closed = True + CloseHandle(self) + + def Detach(self): + if not self.closed: + self.closed = True + return int(self) + raise ValueError("already closed") + + def __repr__(self): + return "Handle(%d)" % int(self) + + __del__ = Close + __str__ = __repr__ + try: MAXFD = os.sysconf("SC_OPEN_MAX") except: @@ -892,11 +913,14 @@ class Popen(object): errread, errwrite = -1, -1 if stdin is None: - p2cread = _subprocess.GetStdHandle(_subprocess.STD_INPUT_HANDLE) + p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE) if p2cread is None: - p2cread, _ = _subprocess.CreatePipe(None, 0) + p2cread, _ = _winapi.CreatePipe(None, 0) + p2cread = Handle(p2cread) + _winapi.CloseHandle(_) elif stdin == PIPE: - p2cread, p2cwrite = _subprocess.CreatePipe(None, 0) + p2cread, p2cwrite = _winapi.CreatePipe(None, 0) + p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) elif stdin == DEVNULL: p2cread = msvcrt.get_osfhandle(self._get_devnull()) elif isinstance(stdin, int): @@ -907,11 +931,14 @@ class Popen(object): p2cread = self._make_inheritable(p2cread) if stdout is None: - c2pwrite = _subprocess.GetStdHandle(_subprocess.STD_OUTPUT_HANDLE) + c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE) if c2pwrite is None: - _, c2pwrite = _subprocess.CreatePipe(None, 0) + _, c2pwrite = _winapi.CreatePipe(None, 0) + c2pwrite = Handle(c2pwrite) + _winapi.CloseHandle(_) elif stdout == PIPE: - c2pread, c2pwrite = _subprocess.CreatePipe(None, 0) + c2pread, c2pwrite = _winapi.CreatePipe(None, 0) + c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) elif stdout == DEVNULL: c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) elif isinstance(stdout, int): @@ -922,11 +949,14 @@ class Popen(object): c2pwrite = self._make_inheritable(c2pwrite) if stderr is None: - errwrite = _subprocess.GetStdHandle(_subprocess.STD_ERROR_HANDLE) + errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE) if errwrite is None: - _, errwrite = _subprocess.CreatePipe(None, 0) + _, errwrite = _winapi.CreatePipe(None, 0) + errwrite = Handle(errwrite) + _winapi.CloseHandle(_) elif stderr == PIPE: - errread, errwrite = _subprocess.CreatePipe(None, 0) + errread, errwrite = _winapi.CreatePipe(None, 0) + errread, errwrite = Handle(errread), Handle(errwrite) elif stderr == STDOUT: errwrite = c2pwrite elif stderr == DEVNULL: @@ -945,15 +975,17 @@ class Popen(object): def _make_inheritable(self, handle): """Return a duplicate of handle, which is inheritable""" - return _subprocess.DuplicateHandle(_subprocess.GetCurrentProcess(), - handle, _subprocess.GetCurrentProcess(), 0, 1, - _subprocess.DUPLICATE_SAME_ACCESS) + h = _winapi.DuplicateHandle( + _winapi.GetCurrentProcess(), handle, + _winapi.GetCurrentProcess(), 0, 1, + _winapi.DUPLICATE_SAME_ACCESS) + return Handle(h) def _find_w9xpopen(self): """Find and return absolut path to w9xpopen.exe""" w9xpopen = os.path.join( - os.path.dirname(_subprocess.GetModuleFileName(0)), + os.path.dirname(_winapi.GetModuleFileName(0)), "w9xpopen.exe") if not os.path.exists(w9xpopen): # Eeek - file-not-found - possibly an embedding @@ -985,17 +1017,17 @@ class Popen(object): if startupinfo is None: startupinfo = STARTUPINFO() if -1 not in (p2cread, c2pwrite, errwrite): - startupinfo.dwFlags |= _subprocess.STARTF_USESTDHANDLES + startupinfo.dwFlags |= _winapi.STARTF_USESTDHANDLES startupinfo.hStdInput = p2cread startupinfo.hStdOutput = c2pwrite startupinfo.hStdError = errwrite if shell: - startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = _subprocess.SW_HIDE + startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = _winapi.SW_HIDE comspec = os.environ.get("COMSPEC", "cmd.exe") args = '{} /c "{}"'.format (comspec, args) - if (_subprocess.GetVersion() >= 0x80000000 or + if (_winapi.GetVersion() >= 0x80000000 or os.path.basename(comspec).lower() == "command.com"): # Win9x, or using command.com on NT. We need to # use the w9xpopen intermediate program. For more @@ -1009,11 +1041,11 @@ class Popen(object): # use at xxx" and a hopeful warning about the # stability of your system. Cost is Ctrl+C won't # kill children. - creationflags |= _subprocess.CREATE_NEW_CONSOLE + creationflags |= _winapi.CREATE_NEW_CONSOLE # Start the process try: - hp, ht, pid, tid = _subprocess.CreateProcess(executable, args, + hp, ht, pid, tid = _winapi.CreateProcess(executable, args, # no special security None, None, int(not close_fds), @@ -1045,14 +1077,14 @@ class Popen(object): # Retain the process handle, but close the thread handle self._child_created = True - self._handle = hp + self._handle = Handle(hp) self.pid = pid - ht.Close() + _winapi.CloseHandle(ht) def _internal_poll(self, _deadstate=None, - _WaitForSingleObject=_subprocess.WaitForSingleObject, - _WAIT_OBJECT_0=_subprocess.WAIT_OBJECT_0, - _GetExitCodeProcess=_subprocess.GetExitCodeProcess): + _WaitForSingleObject=_winapi.WaitForSingleObject, + _WAIT_OBJECT_0=_winapi.WAIT_OBJECT_0, + _GetExitCodeProcess=_winapi.GetExitCodeProcess): """Check if child process has terminated. Returns returncode attribute. @@ -1072,15 +1104,15 @@ class Popen(object): if endtime is not None: timeout = self._remaining_time(endtime) if timeout is None: - timeout_millis = _subprocess.INFINITE + timeout_millis = _winapi.INFINITE else: timeout_millis = int(timeout * 1000) if self.returncode is None: - result = _subprocess.WaitForSingleObject(self._handle, - timeout_millis) - if result == _subprocess.WAIT_TIMEOUT: + result = _winapi.WaitForSingleObject(self._handle, + timeout_millis) + if result == _winapi.WAIT_TIMEOUT: raise TimeoutExpired(self.args, timeout) - self.returncode = _subprocess.GetExitCodeProcess(self._handle) + self.returncode = _winapi.GetExitCodeProcess(self._handle) return self.returncode @@ -1163,12 +1195,12 @@ class Popen(object): """Terminates the process """ try: - _subprocess.TerminateProcess(self._handle, 1) + _winapi.TerminateProcess(self._handle, 1) except PermissionError: # ERROR_ACCESS_DENIED (winerror 5) is received when the # process already died. - rc = _subprocess.GetExitCodeProcess(self._handle) - if rc == _subprocess.STILL_ACTIVE: + rc = _winapi.GetExitCodeProcess(self._handle) + if rc == _winapi.STILL_ACTIVE: raise self.returncode = rc diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index bbde366e5db..f9d58c78dd7 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -84,7 +84,7 @@ HAVE_GETVALUE = not getattr(_multiprocessing, WIN32 = (sys.platform == "win32") if WIN32: - from _subprocess import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 + from _winapi import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 def wait_for_handle(handle, timeout): if timeout is None or timeout < 0.0: diff --git a/Misc/NEWS b/Misc/NEWS index 06fcf2a589c..595136d4357 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Core and Builtins Library ------- +- Issue #11750: The Windows API functions scattered in the _subprocess and + _multiprocessing.win32 modules now live in a single module "_winapi". + Patch by sbt. + - Issue #14087: multiprocessing: add Condition.wait_for(). Patch by sbt. - Issue #14452: SysLogHandler no longer inserts a UTF-8 BOM into the message. diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index d370f9af2c4..6e39a239a69 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -9,8 +9,6 @@ #include "multiprocessing.h" -PyObject *create_win32_namespace(void); - PyObject *ProcessError, *BufferTooShort; /* @@ -66,6 +64,72 @@ multiprocessing_address_of_buffer(PyObject *self, PyObject *obj) PyLong_FromVoidPtr(buffer), buffer_len); } +#ifdef MS_WINDOWS +static PyObject * +multiprocessing_closesocket(PyObject *self, PyObject *args) +{ + HANDLE handle; + int ret; + + if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = closesocket((SOCKET) handle); + Py_END_ALLOW_THREADS + + if (ret) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + Py_RETURN_NONE; +} + +static PyObject * +multiprocessing_recv(PyObject *self, PyObject *args) +{ + HANDLE handle; + int size, nread; + PyObject *buf; + + if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size)) + return NULL; + + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + + Py_BEGIN_ALLOW_THREADS + nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0); + Py_END_ALLOW_THREADS + + if (nread < 0) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + } + _PyBytes_Resize(&buf, nread); + return buf; +} + +static PyObject * +multiprocessing_send(PyObject *self, PyObject *args) +{ + HANDLE handle; + Py_buffer buf; + int ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = send((SOCKET) handle, buf.buf, buf.len, 0); + Py_END_ALLOW_THREADS + + PyBuffer_Release(&buf); + if (ret < 0) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + return PyLong_FromLong(ret); +} + +#endif /* * Function table @@ -75,6 +139,11 @@ static PyMethodDef module_methods[] = { {"address_of_buffer", multiprocessing_address_of_buffer, METH_O, "address_of_buffer(obj) -> int\n" "Return address of obj assuming obj supports buffer inteface"}, +#ifdef MS_WINDOWS + {"closesocket", multiprocessing_closesocket, METH_VARARGS, ""}, + {"recv", multiprocessing_recv, METH_VARARGS, ""}, + {"send", multiprocessing_send, METH_VARARGS, ""}, +#endif {NULL} }; @@ -135,14 +204,6 @@ PyInit__multiprocessing(void) PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType); #endif -#ifdef MS_WINDOWS - /* Initialize win32 class and add to multiprocessing */ - temp = create_win32_namespace(); - if (!temp) - return NULL; - PyModule_AddObject(module, "win32", temp); -#endif - /* Add configuration macros */ temp = PyDict_New(); if (!temp) @@ -152,7 +213,7 @@ PyInit__multiprocessing(void) value = Py_BuildValue("i", name); \ if (value == NULL) { Py_DECREF(temp); return NULL; } \ if (PyDict_SetItemString(temp, #name, value) < 0) { \ - Py_DECREF(temp); Py_DECREF(value); return NULL; } \ + Py_DECREF(temp); Py_DECREF(value); return NULL; } \ Py_DECREF(value) #if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED) diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c deleted file mode 100644 index 93c8fc9cde5..00000000000 --- a/Modules/_multiprocessing/win32_functions.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Win32 functions used by multiprocessing package - * - * win32_functions.c - * - * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt - */ - -#include "multiprocessing.h" - - -#define WIN32_FUNCTION(func) \ - {#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_STATIC, ""} - -#define WIN32_KWARGS_FUNCTION(func) \ - {#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_KEYWORDS | METH_STATIC, ""} - -#define WIN32_CONSTANT(fmt, con) \ - PyDict_SetItemString(Win32Type.tp_dict, #con, Py_BuildValue(fmt, con)) - - -/* Grab CancelIoEx dynamically from kernel32 */ -static int has_CancelIoEx = -1; -static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED); - -static int -check_CancelIoEx() -{ - if (has_CancelIoEx == -1) - { - HINSTANCE hKernel32 = GetModuleHandle("KERNEL32"); - * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32, - "CancelIoEx"); - has_CancelIoEx = (Py_CancelIoEx != NULL); - } - return has_CancelIoEx; -} - - -/* - * A Python object wrapping an OVERLAPPED structure and other useful data - * for overlapped I/O - */ - -typedef struct { - PyObject_HEAD - OVERLAPPED overlapped; - /* For convenience, we store the file handle too */ - HANDLE handle; - /* Whether there's I/O in flight */ - int pending; - /* Whether I/O completed successfully */ - int completed; - /* Buffer used for reading (optional) */ - PyObject *read_buffer; - /* Buffer used for writing (optional) */ - Py_buffer write_buffer; -} OverlappedObject; - -static void -overlapped_dealloc(OverlappedObject *self) -{ - DWORD bytes; - int err = GetLastError(); - if (self->pending) { - /* make it a programming error to deallocate while operation - is pending, even if we can safely cancel it */ - if (check_CancelIoEx() && - Py_CancelIoEx(self->handle, &self->overlapped)) - GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE); - PyErr_SetString(PyExc_RuntimeError, - "I/O operations still in flight while destroying " - "Overlapped object, the process may crash"); - PyErr_WriteUnraisable(NULL); - } - CloseHandle(self->overlapped.hEvent); - SetLastError(err); - if (self->write_buffer.obj) - PyBuffer_Release(&self->write_buffer); - Py_CLEAR(self->read_buffer); - PyObject_Del(self); -} - -static PyObject * -overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *waitobj) -{ - int wait; - BOOL res; - DWORD transferred = 0; - DWORD err; - - wait = PyObject_IsTrue(waitobj); - if (wait < 0) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = GetOverlappedResult(self->handle, &self->overlapped, &transferred, - wait != 0); - Py_END_ALLOW_THREADS - - err = res ? ERROR_SUCCESS : GetLastError(); - switch (err) { - case ERROR_SUCCESS: - case ERROR_MORE_DATA: - case ERROR_OPERATION_ABORTED: - self->completed = 1; - self->pending = 0; - break; - case ERROR_IO_INCOMPLETE: - break; - default: - self->pending = 0; - return PyErr_SetExcFromWindowsErr(PyExc_IOError, err); - } - if (self->completed && self->read_buffer != NULL) { - assert(PyBytes_CheckExact(self->read_buffer)); - if (transferred != PyBytes_GET_SIZE(self->read_buffer) && - _PyBytes_Resize(&self->read_buffer, transferred)) - return NULL; - } - return Py_BuildValue("II", (unsigned) transferred, (unsigned) err); -} - -static PyObject * -overlapped_getbuffer(OverlappedObject *self) -{ - PyObject *res; - if (!self->completed) { - PyErr_SetString(PyExc_ValueError, - "can't get read buffer before GetOverlappedResult() " - "signals the operation completed"); - return NULL; - } - res = self->read_buffer ? self->read_buffer : Py_None; - Py_INCREF(res); - return res; -} - -static PyObject * -overlapped_cancel(OverlappedObject *self) -{ - BOOL res = TRUE; - - if (self->pending) { - Py_BEGIN_ALLOW_THREADS - if (check_CancelIoEx()) - res = Py_CancelIoEx(self->handle, &self->overlapped); - else - res = CancelIo(self->handle); - Py_END_ALLOW_THREADS - } - - /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */ - if (!res && GetLastError() != ERROR_NOT_FOUND) - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - self->pending = 0; - Py_RETURN_NONE; -} - -static PyMethodDef overlapped_methods[] = { - {"GetOverlappedResult", (PyCFunction) overlapped_GetOverlappedResult, - METH_O, NULL}, - {"getbuffer", (PyCFunction) overlapped_getbuffer, METH_NOARGS, NULL}, - {"cancel", (PyCFunction) overlapped_cancel, METH_NOARGS, NULL}, - {NULL} -}; - -static PyMemberDef overlapped_members[] = { - {"event", T_HANDLE, - offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent), - READONLY, "overlapped event handle"}, - {NULL} -}; - -PyTypeObject OverlappedType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_multiprocessing.win32.Overlapped", - /* tp_basicsize */ sizeof(OverlappedObject), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor) overlapped_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ 0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ 0, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT, - /* tp_doc */ "OVERLAPPED structure wrapper", - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ 0, - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ overlapped_methods, - /* tp_members */ overlapped_members, - /* tp_getset */ 0, - /* tp_base */ 0, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ 0, -}; - -static OverlappedObject * -new_overlapped(HANDLE handle) -{ - OverlappedObject *self; - - self = PyObject_New(OverlappedObject, &OverlappedType); - if (!self) - return NULL; - self->handle = handle; - self->read_buffer = NULL; - self->pending = 0; - self->completed = 0; - memset(&self->overlapped, 0, sizeof(OVERLAPPED)); - memset(&self->write_buffer, 0, sizeof(Py_buffer)); - /* Manual reset, initially non-signalled */ - self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - return self; -} - - -/* - * Module functions - */ - -static PyObject * -win32_CloseHandle(PyObject *self, PyObject *args) -{ - HANDLE hObject; - BOOL success; - - if (!PyArg_ParseTuple(args, F_HANDLE, &hObject)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - success = CloseHandle(hObject); - Py_END_ALLOW_THREADS - - if (!success) - return PyErr_SetFromWindowsErr(0); - - Py_RETURN_NONE; -} - -static PyObject * -win32_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds) -{ - HANDLE hNamedPipe; - int use_overlapped = 0; - BOOL success; - OverlappedObject *overlapped = NULL; - static char *kwlist[] = {"handle", "overlapped", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - F_HANDLE "|i", kwlist, - &hNamedPipe, &use_overlapped)) - return NULL; - - if (use_overlapped) { - overlapped = new_overlapped(hNamedPipe); - if (!overlapped) - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - success = ConnectNamedPipe(hNamedPipe, - overlapped ? &overlapped->overlapped : NULL); - Py_END_ALLOW_THREADS - - if (overlapped) { - int err = GetLastError(); - /* Overlapped ConnectNamedPipe never returns a success code */ - assert(success == 0); - if (err == ERROR_IO_PENDING) - overlapped->pending = 1; - else if (err == ERROR_PIPE_CONNECTED) - SetEvent(overlapped->overlapped.hEvent); - else { - Py_DECREF(overlapped); - return PyErr_SetFromWindowsErr(err); - } - return (PyObject *) overlapped; - } - if (!success) - return PyErr_SetFromWindowsErr(0); - - Py_RETURN_NONE; -} - -static PyObject * -win32_CreateFile(PyObject *self, PyObject *args) -{ - LPCTSTR lpFileName; - DWORD dwDesiredAccess; - DWORD dwShareMode; - LPSECURITY_ATTRIBUTES lpSecurityAttributes; - DWORD dwCreationDisposition; - DWORD dwFlagsAndAttributes; - HANDLE hTemplateFile; - HANDLE handle; - - if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_POINTER - F_DWORD F_DWORD F_HANDLE, - &lpFileName, &dwDesiredAccess, &dwShareMode, - &lpSecurityAttributes, &dwCreationDisposition, - &dwFlagsAndAttributes, &hTemplateFile)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - handle = CreateFile(lpFileName, dwDesiredAccess, - dwShareMode, lpSecurityAttributes, - dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); - Py_END_ALLOW_THREADS - - if (handle == INVALID_HANDLE_VALUE) - return PyErr_SetFromWindowsErr(0); - - return Py_BuildValue(F_HANDLE, handle); -} - -static PyObject * -win32_CreateNamedPipe(PyObject *self, PyObject *args) -{ - LPCTSTR lpName; - DWORD dwOpenMode; - DWORD dwPipeMode; - DWORD nMaxInstances; - DWORD nOutBufferSize; - DWORD nInBufferSize; - DWORD nDefaultTimeOut; - LPSECURITY_ATTRIBUTES lpSecurityAttributes; - HANDLE handle; - - if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_DWORD - F_DWORD F_DWORD F_DWORD F_POINTER, - &lpName, &dwOpenMode, &dwPipeMode, - &nMaxInstances, &nOutBufferSize, - &nInBufferSize, &nDefaultTimeOut, - &lpSecurityAttributes)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - handle = CreateNamedPipe(lpName, dwOpenMode, dwPipeMode, - nMaxInstances, nOutBufferSize, - nInBufferSize, nDefaultTimeOut, - lpSecurityAttributes); - Py_END_ALLOW_THREADS - - if (handle == INVALID_HANDLE_VALUE) - return PyErr_SetFromWindowsErr(0); - - return Py_BuildValue(F_HANDLE, handle); -} - -static PyObject * -win32_ExitProcess(PyObject *self, PyObject *args) -{ - UINT uExitCode; - - if (!PyArg_ParseTuple(args, "I", &uExitCode)) - return NULL; - - #if defined(Py_DEBUG) - SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); - #endif - - - ExitProcess(uExitCode); - - return NULL; -} - -static PyObject * -win32_GetLastError(PyObject *self, PyObject *args) -{ - return Py_BuildValue(F_DWORD, GetLastError()); -} - -static PyObject * -win32_OpenProcess(PyObject *self, PyObject *args) -{ - DWORD dwDesiredAccess; - BOOL bInheritHandle; - DWORD dwProcessId; - HANDLE handle; - - if (!PyArg_ParseTuple(args, F_DWORD "i" F_DWORD, - &dwDesiredAccess, &bInheritHandle, &dwProcessId)) - return NULL; - - handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); - if (handle == NULL) - return PyErr_SetFromWindowsErr(0); - - return Py_BuildValue(F_HANDLE, handle); -} - -static PyObject * -win32_SetNamedPipeHandleState(PyObject *self, PyObject *args) -{ - HANDLE hNamedPipe; - PyObject *oArgs[3]; - DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL}; - int i; - - if (!PyArg_ParseTuple(args, F_HANDLE "OOO", - &hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2])) - return NULL; - - PyErr_Clear(); - - for (i = 0 ; i < 3 ; i++) { - if (oArgs[i] != Py_None) { - dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]); - if (PyErr_Occurred()) - return NULL; - pArgs[i] = &dwArgs[i]; - } - } - - if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2])) - return PyErr_SetFromWindowsErr(0); - - Py_RETURN_NONE; -} - -static PyObject * -win32_WaitNamedPipe(PyObject *self, PyObject *args) -{ - LPCTSTR lpNamedPipeName; - DWORD nTimeOut; - BOOL success; - - if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - success = WaitNamedPipe(lpNamedPipeName, nTimeOut); - Py_END_ALLOW_THREADS - - if (!success) - return PyErr_SetFromWindowsErr(0); - - Py_RETURN_NONE; -} - -static PyObject * -win32_closesocket(PyObject *self, PyObject *args) -{ - HANDLE handle; - int ret; - - if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - ret = closesocket((SOCKET) handle); - Py_END_ALLOW_THREADS - - if (ret) - return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); - Py_RETURN_NONE; -} - -static PyObject * -win32_recv(PyObject *self, PyObject *args) -{ - HANDLE handle; - int size, nread; - PyObject *buf; - - if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size)) - return NULL; - - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) - return NULL; - - Py_BEGIN_ALLOW_THREADS - nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0); - Py_END_ALLOW_THREADS - - if (nread < 0) { - Py_DECREF(buf); - return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); - } - _PyBytes_Resize(&buf, nread); - return buf; -} - -static PyObject * -win32_send(PyObject *self, PyObject *args) -{ - HANDLE handle; - Py_buffer buf; - int ret; - - if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - ret = send((SOCKET) handle, buf.buf, buf.len, 0); - Py_END_ALLOW_THREADS - - PyBuffer_Release(&buf); - if (ret < 0) - return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); - return PyLong_FromLong(ret); -} - -static PyObject * -win32_WriteFile(PyObject *self, PyObject *args, PyObject *kwds) -{ - HANDLE handle; - Py_buffer _buf, *buf; - PyObject *bufobj; - DWORD written; - BOOL ret; - int use_overlapped = 0; - DWORD err; - OverlappedObject *overlapped = NULL; - static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; - - /* First get handle and use_overlapped to know which Py_buffer to use */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, - F_HANDLE "O|i:WriteFile", kwlist, - &handle, &bufobj, &use_overlapped)) - return NULL; - - if (use_overlapped) { - overlapped = new_overlapped(handle); - if (!overlapped) - return NULL; - buf = &overlapped->write_buffer; - } - else - buf = &_buf; - - if (!PyArg_Parse(bufobj, "y*", buf)) { - Py_XDECREF(overlapped); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - ret = WriteFile(handle, buf->buf, buf->len, &written, - overlapped ? &overlapped->overlapped : NULL); - Py_END_ALLOW_THREADS - - err = ret ? 0 : GetLastError(); - - if (overlapped) { - if (!ret) { - if (err == ERROR_IO_PENDING) - overlapped->pending = 1; - else { - Py_DECREF(overlapped); - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - } - } - return Py_BuildValue("NI", (PyObject *) overlapped, err); - } - - PyBuffer_Release(buf); - if (!ret) - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - return Py_BuildValue("II", written, err); -} - -static PyObject * -win32_ReadFile(PyObject *self, PyObject *args, PyObject *kwds) -{ - HANDLE handle; - int size; - DWORD nread; - PyObject *buf; - BOOL ret; - int use_overlapped = 0; - DWORD err; - OverlappedObject *overlapped = NULL; - static char *kwlist[] = {"handle", "size", "overlapped", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - F_HANDLE "i|i:ReadFile", kwlist, - &handle, &size, &use_overlapped)) - return NULL; - - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) - return NULL; - if (use_overlapped) { - overlapped = new_overlapped(handle); - if (!overlapped) { - Py_DECREF(buf); - return NULL; - } - /* Steals reference to buf */ - overlapped->read_buffer = buf; - } - - Py_BEGIN_ALLOW_THREADS - ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, - overlapped ? &overlapped->overlapped : NULL); - Py_END_ALLOW_THREADS - - err = ret ? 0 : GetLastError(); - - if (overlapped) { - if (!ret) { - if (err == ERROR_IO_PENDING) - overlapped->pending = 1; - else if (err != ERROR_MORE_DATA) { - Py_DECREF(overlapped); - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - } - } - return Py_BuildValue("NI", (PyObject *) overlapped, err); - } - - if (!ret && err != ERROR_MORE_DATA) { - Py_DECREF(buf); - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - } - if (_PyBytes_Resize(&buf, nread)) - return NULL; - return Py_BuildValue("NI", buf, err); -} - -static PyObject * -win32_PeekNamedPipe(PyObject *self, PyObject *args) -{ - HANDLE handle; - int size = 0; - PyObject *buf = NULL; - DWORD nread, navail, nleft; - BOOL ret; - - if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size)) - return NULL; - - if (size < 0) { - PyErr_SetString(PyExc_ValueError, "negative size"); - return NULL; - } - - if (size) { - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) - return NULL; - Py_BEGIN_ALLOW_THREADS - ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread, - &navail, &nleft); - Py_END_ALLOW_THREADS - if (!ret) { - Py_DECREF(buf); - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - } - if (_PyBytes_Resize(&buf, nread)) - return NULL; - return Py_BuildValue("Nii", buf, navail, nleft); - } - else { - Py_BEGIN_ALLOW_THREADS - ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft); - Py_END_ALLOW_THREADS - if (!ret) { - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - } - return Py_BuildValue("ii", navail, nleft); - } -} - -static PyObject * -win32_WaitForMultipleObjects(PyObject* self, PyObject* args) -{ - DWORD result; - PyObject *handle_seq; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - HANDLE sigint_event = NULL; - Py_ssize_t nhandles, i; - int wait_flag; - int milliseconds = INFINITE; - - if (!PyArg_ParseTuple(args, "Oi|i:WaitForMultipleObjects", - &handle_seq, &wait_flag, &milliseconds)) - return NULL; - - if (!PySequence_Check(handle_seq)) { - PyErr_Format(PyExc_TypeError, - "sequence type expected, got '%s'", - Py_TYPE(handle_seq)->tp_doc); - return NULL; - } - nhandles = PySequence_Length(handle_seq); - if (nhandles == -1) - return NULL; - if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) { - PyErr_Format(PyExc_ValueError, - "need at most %zd handles, got a sequence of length %zd", - MAXIMUM_WAIT_OBJECTS - 1, nhandles); - return NULL; - } - for (i = 0; i < nhandles; i++) { - HANDLE h; - PyObject *v = PySequence_GetItem(handle_seq, i); - if (v == NULL) - return NULL; - if (!PyArg_Parse(v, F_HANDLE, &h)) { - Py_DECREF(v); - return NULL; - } - handles[i] = h; - Py_DECREF(v); - } - /* If this is the main thread then make the wait interruptible - by Ctrl-C unless we are waiting for *all* handles */ - if (!wait_flag && _PyOS_IsMainThread()) { - sigint_event = _PyOS_SigintEvent(); - assert(sigint_event != NULL); - handles[nhandles++] = sigint_event; - } - - Py_BEGIN_ALLOW_THREADS - if (sigint_event != NULL) - ResetEvent(sigint_event); - result = WaitForMultipleObjects((DWORD) nhandles, handles, - (BOOL) wait_flag, (DWORD) milliseconds); - Py_END_ALLOW_THREADS - - if (result == WAIT_FAILED) - return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) { - errno = EINTR; - return PyErr_SetFromErrno(PyExc_IOError); - } - - return PyLong_FromLong((int) result); -} - - -static PyMethodDef win32_methods[] = { - WIN32_FUNCTION(CloseHandle), - WIN32_FUNCTION(GetLastError), - WIN32_FUNCTION(OpenProcess), - WIN32_FUNCTION(ExitProcess), - WIN32_KWARGS_FUNCTION(ConnectNamedPipe), - WIN32_FUNCTION(CreateFile), - WIN32_FUNCTION(CreateNamedPipe), - WIN32_KWARGS_FUNCTION(ReadFile), - WIN32_FUNCTION(PeekNamedPipe), - WIN32_FUNCTION(SetNamedPipeHandleState), - WIN32_FUNCTION(WaitForMultipleObjects), - WIN32_FUNCTION(WaitNamedPipe), - WIN32_KWARGS_FUNCTION(WriteFile), - WIN32_FUNCTION(closesocket), - WIN32_FUNCTION(recv), - WIN32_FUNCTION(send), - {NULL} -}; - - -PyTypeObject Win32Type = { - PyVarObject_HEAD_INIT(NULL, 0) -}; - - -PyObject * -create_win32_namespace(void) -{ - Win32Type.tp_name = "_multiprocessing.win32"; - Win32Type.tp_methods = win32_methods; - if (PyType_Ready(&Win32Type) < 0) - return NULL; - Py_INCREF(&Win32Type); - - if (PyType_Ready(&OverlappedType) < 0) - return NULL; - PyDict_SetItemString(Win32Type.tp_dict, "Overlapped", - (PyObject *) &OverlappedType); - - WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); - WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); - WIN32_CONSTANT(F_DWORD, ERROR_IO_PENDING); - WIN32_CONSTANT(F_DWORD, ERROR_MORE_DATA); - WIN32_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); - WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); - WIN32_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); - WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); - WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); - WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); - WIN32_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); - WIN32_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); - WIN32_CONSTANT(F_DWORD, GENERIC_READ); - WIN32_CONSTANT(F_DWORD, GENERIC_WRITE); - WIN32_CONSTANT(F_DWORD, INFINITE); - WIN32_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER); - WIN32_CONSTANT(F_DWORD, OPEN_EXISTING); - WIN32_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX); - WIN32_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND); - WIN32_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE); - WIN32_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE); - WIN32_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES); - WIN32_CONSTANT(F_DWORD, PIPE_WAIT); - WIN32_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS); - - WIN32_CONSTANT("i", NULL); - - return (PyObject*)&Win32Type; -} diff --git a/Modules/_winapi.c b/Modules/_winapi.c new file mode 100644 index 00000000000..4b9455edc96 --- /dev/null +++ b/Modules/_winapi.c @@ -0,0 +1,1326 @@ +/* + * Support routines from the Windows API + * + * This module was originally created by merging PC/_subprocess.c with + * Modules/_multiprocessing/win32_functions.c. + * + * Copyright (c) 2004 by Fredrik Lundh + * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com + * Copyright (c) 2004 by Peter Astrand + * + * By obtaining, using, and/or copying this software and/or its + * associated documentation, you agree that you have read, understood, + * and will comply with the following terms and conditions: + * + * Permission to use, copy, modify, and distribute this software and + * its associated documentation for any purpose and without fee is + * hereby granted, provided that the above copyright notice appears in + * all copies, and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of the + * authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Licensed to PSF under a Contributor Agreement. */ +/* See http://www.python.org/2.4/license for licensing details. */ + +#include "Python.h" +#include "structmember.h" + +#define WINDOWS_LEAN_AND_MEAN +#include "windows.h" +#include + +#if defined(MS_WIN32) && !defined(MS_WIN64) +#define HANDLE_TO_PYNUM(handle) \ + PyLong_FromUnsignedLong((unsigned long) handle) +#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj)) +#define F_POINTER "k" +#define T_POINTER T_ULONG +#else +#define HANDLE_TO_PYNUM(handle) \ + PyLong_FromUnsignedLongLong((unsigned long long) handle) +#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj)) +#define F_POINTER "K" +#define T_POINTER T_ULONGLONG +#endif + +#define F_HANDLE F_POINTER +#define F_DWORD "k" +#define F_BOOL "i" +#define F_UINT "I" + +#define T_HANDLE T_POINTER + +/* Grab CancelIoEx dynamically from kernel32 */ +static int has_CancelIoEx = -1; +static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED); + +static int +check_CancelIoEx() +{ + if (has_CancelIoEx == -1) + { + HINSTANCE hKernel32 = GetModuleHandle("KERNEL32"); + * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32, + "CancelIoEx"); + has_CancelIoEx = (Py_CancelIoEx != NULL); + } + return has_CancelIoEx; +} + + +/* + * A Python object wrapping an OVERLAPPED structure and other useful data + * for overlapped I/O + */ + +typedef struct { + PyObject_HEAD + OVERLAPPED overlapped; + /* For convenience, we store the file handle too */ + HANDLE handle; + /* Whether there's I/O in flight */ + int pending; + /* Whether I/O completed successfully */ + int completed; + /* Buffer used for reading (optional) */ + PyObject *read_buffer; + /* Buffer used for writing (optional) */ + Py_buffer write_buffer; +} OverlappedObject; + +static void +overlapped_dealloc(OverlappedObject *self) +{ + DWORD bytes; + int err = GetLastError(); + if (self->pending) { + /* make it a programming error to deallocate while operation + is pending, even if we can safely cancel it */ + if (check_CancelIoEx() && + Py_CancelIoEx(self->handle, &self->overlapped)) + GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE); + PyErr_SetString(PyExc_RuntimeError, + "I/O operations still in flight while destroying " + "Overlapped object, the process may crash"); + PyErr_WriteUnraisable(NULL); + } + CloseHandle(self->overlapped.hEvent); + SetLastError(err); + if (self->write_buffer.obj) + PyBuffer_Release(&self->write_buffer); + Py_CLEAR(self->read_buffer); + PyObject_Del(self); +} + +static PyObject * +overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *waitobj) +{ + int wait; + BOOL res; + DWORD transferred = 0; + DWORD err; + + wait = PyObject_IsTrue(waitobj); + if (wait < 0) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = GetOverlappedResult(self->handle, &self->overlapped, &transferred, + wait != 0); + Py_END_ALLOW_THREADS + + err = res ? ERROR_SUCCESS : GetLastError(); + switch (err) { + case ERROR_SUCCESS: + case ERROR_MORE_DATA: + case ERROR_OPERATION_ABORTED: + self->completed = 1; + self->pending = 0; + break; + case ERROR_IO_INCOMPLETE: + break; + default: + self->pending = 0; + return PyErr_SetExcFromWindowsErr(PyExc_IOError, err); + } + if (self->completed && self->read_buffer != NULL) { + assert(PyBytes_CheckExact(self->read_buffer)); + if (transferred != PyBytes_GET_SIZE(self->read_buffer) && + _PyBytes_Resize(&self->read_buffer, transferred)) + return NULL; + } + return Py_BuildValue("II", (unsigned) transferred, (unsigned) err); +} + +static PyObject * +overlapped_getbuffer(OverlappedObject *self) +{ + PyObject *res; + if (!self->completed) { + PyErr_SetString(PyExc_ValueError, + "can't get read buffer before GetOverlappedResult() " + "signals the operation completed"); + return NULL; + } + res = self->read_buffer ? self->read_buffer : Py_None; + Py_INCREF(res); + return res; +} + +static PyObject * +overlapped_cancel(OverlappedObject *self) +{ + BOOL res = TRUE; + + if (self->pending) { + Py_BEGIN_ALLOW_THREADS + if (check_CancelIoEx()) + res = Py_CancelIoEx(self->handle, &self->overlapped); + else + res = CancelIo(self->handle); + Py_END_ALLOW_THREADS + } + + /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */ + if (!res && GetLastError() != ERROR_NOT_FOUND) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + self->pending = 0; + Py_RETURN_NONE; +} + +static PyMethodDef overlapped_methods[] = { + {"GetOverlappedResult", (PyCFunction) overlapped_GetOverlappedResult, + METH_O, NULL}, + {"getbuffer", (PyCFunction) overlapped_getbuffer, METH_NOARGS, NULL}, + {"cancel", (PyCFunction) overlapped_cancel, METH_NOARGS, NULL}, + {NULL} +}; + +static PyMemberDef overlapped_members[] = { + {"event", T_HANDLE, + offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent), + READONLY, "overlapped event handle"}, + {NULL} +}; + +PyTypeObject OverlappedType = { + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_winapi.Overlapped", + /* tp_basicsize */ sizeof(OverlappedObject), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) overlapped_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ 0, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT, + /* tp_doc */ "OVERLAPPED structure wrapper", + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ overlapped_methods, + /* tp_members */ overlapped_members, + /* tp_getset */ 0, + /* tp_base */ 0, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ 0, +}; + +static OverlappedObject * +new_overlapped(HANDLE handle) +{ + OverlappedObject *self; + + self = PyObject_New(OverlappedObject, &OverlappedType); + if (!self) + return NULL; + self->handle = handle; + self->read_buffer = NULL; + self->pending = 0; + self->completed = 0; + memset(&self->overlapped, 0, sizeof(OVERLAPPED)); + memset(&self->write_buffer, 0, sizeof(Py_buffer)); + /* Manual reset, initially non-signalled */ + self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return self; +} + +/* -------------------------------------------------------------------- */ +/* windows API functions */ + +PyDoc_STRVAR(CloseHandle_doc, +"CloseHandle(handle) -> None\n\ +\n\ +Close handle."); + +static PyObject * +winapi_CloseHandle(PyObject *self, PyObject *args) +{ + HANDLE hObject; + BOOL success; + + if (!PyArg_ParseTuple(args, F_HANDLE ":CloseHandle", &hObject)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + success = CloseHandle(hObject); + Py_END_ALLOW_THREADS + + if (!success) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + +static PyObject * +winapi_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds) +{ + HANDLE hNamedPipe; + int use_overlapped = 0; + BOOL success; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "overlapped", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "|" F_BOOL, kwlist, + &hNamedPipe, &use_overlapped)) + return NULL; + + if (use_overlapped) { + overlapped = new_overlapped(hNamedPipe); + if (!overlapped) + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + success = ConnectNamedPipe(hNamedPipe, + overlapped ? &overlapped->overlapped : NULL); + Py_END_ALLOW_THREADS + + if (overlapped) { + int err = GetLastError(); + /* Overlapped ConnectNamedPipe never returns a success code */ + assert(success == 0); + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else if (err == ERROR_PIPE_CONNECTED) + SetEvent(overlapped->overlapped.hEvent); + else { + Py_DECREF(overlapped); + return PyErr_SetFromWindowsErr(err); + } + return (PyObject *) overlapped; + } + if (!success) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + +static PyObject * +winapi_CreateFile(PyObject *self, PyObject *args) +{ + LPCTSTR lpFileName; + DWORD dwDesiredAccess; + DWORD dwShareMode; + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; + HANDLE hTemplateFile; + HANDLE handle; + + if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_POINTER + F_DWORD F_DWORD F_HANDLE, + &lpFileName, &dwDesiredAccess, &dwShareMode, + &lpSecurityAttributes, &dwCreationDisposition, + &dwFlagsAndAttributes, &hTemplateFile)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + handle = CreateFile(lpFileName, dwDesiredAccess, + dwShareMode, lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + Py_END_ALLOW_THREADS + + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(0); + + return Py_BuildValue(F_HANDLE, handle); +} + +static PyObject * +winapi_CreateNamedPipe(PyObject *self, PyObject *args) +{ + LPCTSTR lpName; + DWORD dwOpenMode; + DWORD dwPipeMode; + DWORD nMaxInstances; + DWORD nOutBufferSize; + DWORD nInBufferSize; + DWORD nDefaultTimeOut; + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + HANDLE handle; + + if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_DWORD + F_DWORD F_DWORD F_DWORD F_POINTER, + &lpName, &dwOpenMode, &dwPipeMode, + &nMaxInstances, &nOutBufferSize, + &nInBufferSize, &nDefaultTimeOut, + &lpSecurityAttributes)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + handle = CreateNamedPipe(lpName, dwOpenMode, dwPipeMode, + nMaxInstances, nOutBufferSize, + nInBufferSize, nDefaultTimeOut, + lpSecurityAttributes); + Py_END_ALLOW_THREADS + + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(0); + + return Py_BuildValue(F_HANDLE, handle); +} + +PyDoc_STRVAR(CreatePipe_doc, +"CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\ +\n\ +Create an anonymous pipe, and return handles to the read and\n\ +write ends of the pipe.\n\ +\n\ +pipe_attrs is ignored internally and can be None."); + +static PyObject * +winapi_CreatePipe(PyObject* self, PyObject* args) +{ + HANDLE read_pipe; + HANDLE write_pipe; + BOOL result; + + PyObject* pipe_attributes; /* ignored */ + DWORD size; + + if (! PyArg_ParseTuple(args, "O" F_DWORD ":CreatePipe", + &pipe_attributes, &size)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = CreatePipe(&read_pipe, &write_pipe, NULL, size); + Py_END_ALLOW_THREADS + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue( + "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe)); +} + +/* helpers for createprocess */ + +static unsigned long +getulong(PyObject* obj, char* name) +{ + PyObject* value; + unsigned long ret; + + value = PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return 0; + } + ret = PyLong_AsUnsignedLong(value); + Py_DECREF(value); + return ret; +} + +static HANDLE +gethandle(PyObject* obj, char* name) +{ + PyObject* value; + HANDLE ret; + + value = PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return NULL; + } + if (value == Py_None) + ret = NULL; + else + ret = PYNUM_TO_HANDLE(value); + Py_DECREF(value); + return ret; +} + +static PyObject* +getenvironment(PyObject* environment) +{ + Py_ssize_t i, envsize, totalsize; + Py_UCS4 *buffer = NULL, *p, *end; + PyObject *keys, *values, *res; + + /* convert environment dictionary to windows enviroment string */ + if (! PyMapping_Check(environment)) { + PyErr_SetString( + PyExc_TypeError, "environment must be dictionary or None"); + return NULL; + } + + envsize = PyMapping_Length(environment); + + keys = PyMapping_Keys(environment); + values = PyMapping_Values(environment); + if (!keys || !values) + goto error; + + totalsize = 1; /* trailing null character */ + for (i = 0; i < envsize; i++) { + PyObject* key = PyList_GET_ITEM(keys, i); + PyObject* value = PyList_GET_ITEM(values, i); + + if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "environment can only contain strings"); + goto error; + } + totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ + totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ + } + + buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); + if (! buffer) + goto error; + p = buffer; + end = buffer + totalsize; + + for (i = 0; i < envsize; i++) { + PyObject* key = PyList_GET_ITEM(keys, i); + PyObject* value = PyList_GET_ITEM(values, i); + if (!PyUnicode_AsUCS4(key, p, end - p, 0)) + goto error; + p += PyUnicode_GET_LENGTH(key); + *p++ = '='; + if (!PyUnicode_AsUCS4(value, p, end - p, 0)) + goto error; + p += PyUnicode_GET_LENGTH(value); + *p++ = '\0'; + } + + /* add trailing null byte */ + *p++ = '\0'; + assert(p == end); + + Py_XDECREF(keys); + Py_XDECREF(values); + + res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer); + PyMem_Free(buffer); + return res; + + error: + PyMem_Free(buffer); + Py_XDECREF(keys); + Py_XDECREF(values); + return NULL; +} + +PyDoc_STRVAR(CreateProcess_doc, +"CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\ + inherit, flags, env_mapping, curdir,\n\ + startup_info) -> (proc_handle, thread_handle,\n\ + pid, tid)\n\ +\n\ +Create a new process and its primary thread. The return\n\ +value is a tuple of the process handle, thread handle,\n\ +process ID, and thread ID.\n\ +\n\ +proc_attrs and thread_attrs are ignored internally and can be None."); + +static PyObject * +winapi_CreateProcess(PyObject* self, PyObject* args) +{ + BOOL result; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + PyObject* environment; + wchar_t *wenvironment; + + wchar_t* application_name; + wchar_t* command_line; + PyObject* process_attributes; /* ignored */ + PyObject* thread_attributes; /* ignored */ + BOOL inherit_handles; + DWORD creation_flags; + PyObject* env_mapping; + wchar_t* current_directory; + PyObject* startup_info; + + if (! PyArg_ParseTuple(args, "ZZOO" F_BOOL F_DWORD "OZO:CreateProcess", + &application_name, + &command_line, + &process_attributes, + &thread_attributes, + &inherit_handles, + &creation_flags, + &env_mapping, + ¤t_directory, + &startup_info)) + return NULL; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + /* note: we only support a small subset of all SI attributes */ + si.dwFlags = getulong(startup_info, "dwFlags"); + si.wShowWindow = (WORD)getulong(startup_info, "wShowWindow"); + si.hStdInput = gethandle(startup_info, "hStdInput"); + si.hStdOutput = gethandle(startup_info, "hStdOutput"); + si.hStdError = gethandle(startup_info, "hStdError"); + if (PyErr_Occurred()) + return NULL; + + if (env_mapping != Py_None) { + environment = getenvironment(env_mapping); + if (! environment) + return NULL; + wenvironment = PyUnicode_AsUnicode(environment); + if (wenvironment == NULL) + { + Py_XDECREF(environment); + return NULL; + } + } + else { + environment = NULL; + wenvironment = NULL; + } + + Py_BEGIN_ALLOW_THREADS + result = CreateProcessW(application_name, + command_line, + NULL, + NULL, + inherit_handles, + creation_flags | CREATE_UNICODE_ENVIRONMENT, + wenvironment, + current_directory, + &si, + &pi); + Py_END_ALLOW_THREADS + + Py_XDECREF(environment); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue("NNkk", + HANDLE_TO_PYNUM(pi.hProcess), + HANDLE_TO_PYNUM(pi.hThread), + pi.dwProcessId, + pi.dwThreadId); +} + +PyDoc_STRVAR(DuplicateHandle_doc, +"DuplicateHandle(source_proc_handle, source_handle,\n\ + target_proc_handle, target_handle, access,\n\ + inherit[, options]) -> handle\n\ +\n\ +Return a duplicate handle object.\n\ +\n\ +The duplicate handle refers to the same object as the original\n\ +handle. Therefore, any changes to the object are reflected\n\ +through both handles."); + +static PyObject * +winapi_DuplicateHandle(PyObject* self, PyObject* args) +{ + HANDLE target_handle; + BOOL result; + + HANDLE source_process_handle; + HANDLE source_handle; + HANDLE target_process_handle; + DWORD desired_access; + BOOL inherit_handle; + DWORD options = 0; + + if (! PyArg_ParseTuple(args, + F_HANDLE F_HANDLE F_HANDLE F_DWORD F_BOOL F_DWORD + ":DuplicateHandle", + &source_process_handle, + &source_handle, + &target_process_handle, + &desired_access, + &inherit_handle, + &options)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = DuplicateHandle( + source_process_handle, + source_handle, + target_process_handle, + &target_handle, + desired_access, + inherit_handle, + options + ); + Py_END_ALLOW_THREADS + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return HANDLE_TO_PYNUM(target_handle); +} + +static PyObject * +winapi_ExitProcess(PyObject *self, PyObject *args) +{ + UINT uExitCode; + + if (!PyArg_ParseTuple(args, F_UINT, &uExitCode)) + return NULL; + + #if defined(Py_DEBUG) + SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT| + SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + #endif + + ExitProcess(uExitCode); + + return NULL; +} + +PyDoc_STRVAR(GetCurrentProcess_doc, +"GetCurrentProcess() -> handle\n\ +\n\ +Return a handle object for the current process."); + +static PyObject * +winapi_GetCurrentProcess(PyObject* self, PyObject* args) +{ + if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) + return NULL; + + return HANDLE_TO_PYNUM(GetCurrentProcess()); +} + +PyDoc_STRVAR(GetExitCodeProcess_doc, +"GetExitCodeProcess(handle) -> Exit code\n\ +\n\ +Return the termination status of the specified process."); + +static PyObject * +winapi_GetExitCodeProcess(PyObject* self, PyObject* args) +{ + DWORD exit_code; + BOOL result; + + HANDLE process; + if (! PyArg_ParseTuple(args, F_HANDLE ":GetExitCodeProcess", &process)) + return NULL; + + result = GetExitCodeProcess(process, &exit_code); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyLong_FromUnsignedLong(exit_code); +} + +static PyObject * +winapi_GetLastError(PyObject *self, PyObject *args) +{ + return Py_BuildValue(F_DWORD, GetLastError()); +} + +PyDoc_STRVAR(GetModuleFileName_doc, +"GetModuleFileName(module) -> path\n\ +\n\ +Return the fully-qualified path for the file that contains\n\ +the specified module. The module must have been loaded by the\n\ +current process.\n\ +\n\ +The module parameter should be a handle to the loaded module\n\ +whose path is being requested. If this parameter is 0, \n\ +GetModuleFileName retrieves the path of the executable file\n\ +of the current process."); + +static PyObject * +winapi_GetModuleFileName(PyObject* self, PyObject* args) +{ + BOOL result; + HMODULE module; + WCHAR filename[MAX_PATH]; + + if (! PyArg_ParseTuple(args, F_HANDLE ":GetModuleFileName", + &module)) + return NULL; + + result = GetModuleFileNameW(module, filename, MAX_PATH); + filename[MAX_PATH-1] = '\0'; + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyUnicode_FromWideChar(filename, wcslen(filename)); +} + +PyDoc_STRVAR(GetStdHandle_doc, +"GetStdHandle(handle) -> integer\n\ +\n\ +Return a handle to the specified standard device\n\ +(STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\ +The integer associated with the handle object is returned."); + +static PyObject * +winapi_GetStdHandle(PyObject* self, PyObject* args) +{ + HANDLE handle; + DWORD std_handle; + + if (! PyArg_ParseTuple(args, F_DWORD ":GetStdHandle", &std_handle)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + handle = GetStdHandle(std_handle); + Py_END_ALLOW_THREADS + + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(GetLastError()); + + if (! handle) { + Py_INCREF(Py_None); + return Py_None; + } + + /* note: returns integer, not handle object */ + return HANDLE_TO_PYNUM(handle); +} + +PyDoc_STRVAR(GetVersion_doc, +"GetVersion() -> version\n\ +\n\ +Return the version number of the current operating system."); + +static PyObject * +winapi_GetVersion(PyObject* self, PyObject* args) +{ + if (! PyArg_ParseTuple(args, ":GetVersion")) + return NULL; + + return PyLong_FromUnsignedLong(GetVersion()); +} + +static PyObject * +winapi_OpenProcess(PyObject *self, PyObject *args) +{ + DWORD dwDesiredAccess; + BOOL bInheritHandle; + DWORD dwProcessId; + HANDLE handle; + + if (!PyArg_ParseTuple(args, F_DWORD F_BOOL F_DWORD, + &dwDesiredAccess, &bInheritHandle, &dwProcessId)) + return NULL; + + handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); + if (handle == NULL) + return PyErr_SetFromWindowsErr(0); + + return Py_BuildValue(F_HANDLE, handle); +} + +static PyObject * +winapi_PeekNamedPipe(PyObject *self, PyObject *args) +{ + HANDLE handle; + int size = 0; + PyObject *buf = NULL; + DWORD nread, navail, nleft; + BOOL ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size)) + return NULL; + + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative size"); + return NULL; + } + + if (size) { + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + Py_BEGIN_ALLOW_THREADS + ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread, + &navail, &nleft); + Py_END_ALLOW_THREADS + if (!ret) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + if (_PyBytes_Resize(&buf, nread)) + return NULL; + return Py_BuildValue("Nii", buf, navail, nleft); + } + else { + Py_BEGIN_ALLOW_THREADS + ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft); + Py_END_ALLOW_THREADS + if (!ret) { + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + return Py_BuildValue("ii", navail, nleft); + } +} + +static PyObject * +winapi_ReadFile(PyObject *self, PyObject *args, PyObject *kwds) +{ + HANDLE handle; + int size; + DWORD nread; + PyObject *buf; + BOOL ret; + int use_overlapped = 0; + DWORD err; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "size", "overlapped", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "i|i:ReadFile", kwlist, + &handle, &size, &use_overlapped)) + return NULL; + + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + if (use_overlapped) { + overlapped = new_overlapped(handle); + if (!overlapped) { + Py_DECREF(buf); + return NULL; + } + /* Steals reference to buf */ + overlapped->read_buffer = buf; + } + + Py_BEGIN_ALLOW_THREADS + ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, + overlapped ? &overlapped->overlapped : NULL); + Py_END_ALLOW_THREADS + + err = ret ? 0 : GetLastError(); + + if (overlapped) { + if (!ret) { + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else if (err != ERROR_MORE_DATA) { + Py_DECREF(overlapped); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + } + return Py_BuildValue("NI", (PyObject *) overlapped, err); + } + + if (!ret && err != ERROR_MORE_DATA) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + if (_PyBytes_Resize(&buf, nread)) + return NULL; + return Py_BuildValue("NI", buf, err); +} + +static PyObject * +winapi_SetNamedPipeHandleState(PyObject *self, PyObject *args) +{ + HANDLE hNamedPipe; + PyObject *oArgs[3]; + DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL}; + int i; + + if (!PyArg_ParseTuple(args, F_HANDLE "OOO", + &hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2])) + return NULL; + + PyErr_Clear(); + + for (i = 0 ; i < 3 ; i++) { + if (oArgs[i] != Py_None) { + dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]); + if (PyErr_Occurred()) + return NULL; + pArgs[i] = &dwArgs[i]; + } + } + + if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2])) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(TerminateProcess_doc, +"TerminateProcess(handle, exit_code) -> None\n\ +\n\ +Terminate the specified process and all of its threads."); + +static PyObject * +winapi_TerminateProcess(PyObject* self, PyObject* args) +{ + BOOL result; + + HANDLE process; + UINT exit_code; + if (! PyArg_ParseTuple(args, F_HANDLE F_UINT ":TerminateProcess", + &process, &exit_code)) + return NULL; + + result = TerminateProcess(process, exit_code); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +winapi_WaitNamedPipe(PyObject *self, PyObject *args) +{ + LPCTSTR lpNamedPipeName; + DWORD nTimeOut; + BOOL success; + + if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + success = WaitNamedPipe(lpNamedPipeName, nTimeOut); + Py_END_ALLOW_THREADS + + if (!success) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + +static PyObject * +winapi_WaitForMultipleObjects(PyObject* self, PyObject* args) +{ + DWORD result; + PyObject *handle_seq; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + HANDLE sigint_event = NULL; + Py_ssize_t nhandles, i; + BOOL wait_flag; + DWORD milliseconds = INFINITE; + + if (!PyArg_ParseTuple(args, "O" F_BOOL "|" F_DWORD + ":WaitForMultipleObjects", + &handle_seq, &wait_flag, &milliseconds)) + return NULL; + + if (!PySequence_Check(handle_seq)) { + PyErr_Format(PyExc_TypeError, + "sequence type expected, got '%s'", + Py_TYPE(handle_seq)->tp_doc); + return NULL; + } + nhandles = PySequence_Length(handle_seq); + if (nhandles == -1) + return NULL; + if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) { + PyErr_Format(PyExc_ValueError, + "need at most %zd handles, got a sequence of length %zd", + MAXIMUM_WAIT_OBJECTS - 1, nhandles); + return NULL; + } + for (i = 0; i < nhandles; i++) { + HANDLE h; + PyObject *v = PySequence_GetItem(handle_seq, i); + if (v == NULL) + return NULL; + if (!PyArg_Parse(v, F_HANDLE, &h)) { + Py_DECREF(v); + return NULL; + } + handles[i] = h; + Py_DECREF(v); + } + /* If this is the main thread then make the wait interruptible + by Ctrl-C unless we are waiting for *all* handles */ + if (!wait_flag && _PyOS_IsMainThread()) { + sigint_event = _PyOS_SigintEvent(); + assert(sigint_event != NULL); + handles[nhandles++] = sigint_event; + } + + Py_BEGIN_ALLOW_THREADS + if (sigint_event != NULL) + ResetEvent(sigint_event); + result = WaitForMultipleObjects((DWORD) nhandles, handles, + wait_flag, milliseconds); + Py_END_ALLOW_THREADS + + if (result == WAIT_FAILED) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) { + errno = EINTR; + return PyErr_SetFromErrno(PyExc_IOError); + } + + return PyLong_FromLong((int) result); +} + +PyDoc_STRVAR(WaitForSingleObject_doc, +"WaitForSingleObject(handle, timeout) -> result\n\ +\n\ +Wait until the specified object is in the signaled state or\n\ +the time-out interval elapses. The timeout value is specified\n\ +in milliseconds."); + +static PyObject * +winapi_WaitForSingleObject(PyObject* self, PyObject* args) +{ + DWORD result; + + HANDLE handle; + DWORD milliseconds; + if (! PyArg_ParseTuple(args, F_HANDLE F_DWORD ":WaitForSingleObject", + &handle, + &milliseconds)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = WaitForSingleObject(handle, milliseconds); + Py_END_ALLOW_THREADS + + if (result == WAIT_FAILED) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyLong_FromUnsignedLong(result); +} + +static PyObject * +winapi_WriteFile(PyObject *self, PyObject *args, PyObject *kwds) +{ + HANDLE handle; + Py_buffer _buf, *buf; + PyObject *bufobj; + DWORD written; + BOOL ret; + int use_overlapped = 0; + DWORD err; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; + + /* First get handle and use_overlapped to know which Py_buffer to use */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "O|i:WriteFile", kwlist, + &handle, &bufobj, &use_overlapped)) + return NULL; + + if (use_overlapped) { + overlapped = new_overlapped(handle); + if (!overlapped) + return NULL; + buf = &overlapped->write_buffer; + } + else + buf = &_buf; + + if (!PyArg_Parse(bufobj, "y*", buf)) { + Py_XDECREF(overlapped); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + ret = WriteFile(handle, buf->buf, buf->len, &written, + overlapped ? &overlapped->overlapped : NULL); + Py_END_ALLOW_THREADS + + err = ret ? 0 : GetLastError(); + + if (overlapped) { + if (!ret) { + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else { + Py_DECREF(overlapped); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + } + return Py_BuildValue("NI", (PyObject *) overlapped, err); + } + + PyBuffer_Release(buf); + if (!ret) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + return Py_BuildValue("II", written, err); +} + + +static PyMethodDef winapi_functions[] = { + {"CloseHandle", winapi_CloseHandle, METH_VARARGS, + CloseHandle_doc}, + {"ConnectNamedPipe", (PyCFunction)winapi_ConnectNamedPipe, + METH_VARARGS | METH_KEYWORDS, ""}, + {"CreateFile", winapi_CreateFile, METH_VARARGS, + ""}, + {"CreateNamedPipe", winapi_CreateNamedPipe, METH_VARARGS, + ""}, + {"CreatePipe", winapi_CreatePipe, METH_VARARGS, + CreatePipe_doc}, + {"CreateProcess", winapi_CreateProcess, METH_VARARGS, + CreateProcess_doc}, + {"DuplicateHandle", winapi_DuplicateHandle, METH_VARARGS, + DuplicateHandle_doc}, + {"ExitProcess", winapi_ExitProcess, METH_VARARGS, + ""}, + {"GetCurrentProcess", winapi_GetCurrentProcess, METH_VARARGS, + GetCurrentProcess_doc}, + {"GetExitCodeProcess", winapi_GetExitCodeProcess, METH_VARARGS, + GetExitCodeProcess_doc}, + {"GetLastError", winapi_GetLastError, METH_NOARGS, + GetCurrentProcess_doc}, + {"GetModuleFileName", winapi_GetModuleFileName, METH_VARARGS, + GetModuleFileName_doc}, + {"GetStdHandle", winapi_GetStdHandle, METH_VARARGS, + GetStdHandle_doc}, + {"GetVersion", winapi_GetVersion, METH_VARARGS, + GetVersion_doc}, + {"OpenProcess", winapi_OpenProcess, METH_VARARGS, + ""}, + {"PeekNamedPipe", winapi_PeekNamedPipe, METH_VARARGS, + ""}, + {"ReadFile", (PyCFunction)winapi_ReadFile, METH_VARARGS | METH_KEYWORDS, + ""}, + {"SetNamedPipeHandleState", winapi_SetNamedPipeHandleState, METH_VARARGS, + ""}, + {"TerminateProcess", winapi_TerminateProcess, METH_VARARGS, + TerminateProcess_doc}, + {"WaitNamedPipe", winapi_WaitNamedPipe, METH_VARARGS, + ""}, + {"WaitForMultipleObjects", winapi_WaitForMultipleObjects, METH_VARARGS, + ""}, + {"WaitForSingleObject", winapi_WaitForSingleObject, METH_VARARGS, + WaitForSingleObject_doc}, + {"WriteFile", (PyCFunction)winapi_WriteFile, METH_VARARGS | METH_KEYWORDS, + ""}, + {NULL, NULL} +}; + +static struct PyModuleDef winapi_module = { + PyModuleDef_HEAD_INIT, + "_winapi", + NULL, + -1, + winapi_functions, + NULL, + NULL, + NULL, + NULL +}; + +#define WINAPI_CONSTANT(fmt, con) \ + PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con)) + +PyMODINIT_FUNC +PyInit__winapi(void) +{ + PyObject *d; + PyObject *m; + + if (PyType_Ready(&OverlappedType) < 0) + return NULL; + + m = PyModule_Create(&winapi_module); + if (m == NULL) + return NULL; + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType); + + /* constants */ + WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE); + WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP); + WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS); + WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); + WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); + WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); + WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA); + WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); + WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); + WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); + WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); + WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); + WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA); + WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); + WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); + WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); + WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); + WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); + WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); + WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); + WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); + WINAPI_CONSTANT(F_DWORD, GENERIC_READ); + WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE); + WINAPI_CONSTANT(F_DWORD, INFINITE); + WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER); + WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING); + WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX); + WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND); + WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE); + WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE); + WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES); + WINAPI_CONSTANT(F_DWORD, PIPE_WAIT); + WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS); + WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW); + WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES); + WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE); + WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE); + WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE); + WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE); + WINAPI_CONSTANT(F_DWORD, SW_HIDE); + WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0); + WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT); + + WINAPI_CONSTANT("i", NULL); + + return m; +} diff --git a/PC/_subprocess.c b/PC/_subprocess.c deleted file mode 100644 index 13a5e1f1944..00000000000 --- a/PC/_subprocess.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * support routines for subprocess module - * - * Currently, this extension module is only required when using the - * subprocess module on Windows, but in the future, stubs for other - * platforms might be added here as well. - * - * Copyright (c) 2004 by Fredrik Lundh - * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com - * Copyright (c) 2004 by Peter Astrand - * - * By obtaining, using, and/or copying this software and/or its - * associated documentation, you agree that you have read, understood, - * and will comply with the following terms and conditions: - * - * Permission to use, copy, modify, and distribute this software and - * its associated documentation for any purpose and without fee is - * hereby granted, provided that the above copyright notice appears in - * all copies, and that both that copyright notice and this permission - * notice appear in supporting documentation, and that the name of the - * authors not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. - * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -/* Licensed to PSF under a Contributor Agreement. */ -/* See http://www.python.org/2.4/license for licensing details. */ - -#include "Python.h" - -#define WINDOWS_LEAN_AND_MEAN -#include "windows.h" - -/* -------------------------------------------------------------------- */ -/* handle wrapper. note that this library uses integers when passing - handles to a function, and handle wrappers when returning handles. - the wrapper is used to provide Detach and Close methods */ - -typedef struct { - PyObject_HEAD - HANDLE handle; -} sp_handle_object; - -static PyTypeObject sp_handle_type; - -static PyObject* -sp_handle_new(HANDLE handle) -{ - sp_handle_object* self; - - self = PyObject_NEW(sp_handle_object, &sp_handle_type); - if (self == NULL) - return NULL; - - self->handle = handle; - - return (PyObject*) self; -} - -#if defined(MS_WIN32) && !defined(MS_WIN64) -#define HANDLE_TO_PYNUM(handle) PyLong_FromLong((long) handle) -#define PY_HANDLE_PARAM "l" -#else -#define HANDLE_TO_PYNUM(handle) PyLong_FromLongLong((long long) handle) -#define PY_HANDLE_PARAM "L" -#endif - -static PyObject* -sp_handle_detach(sp_handle_object* self, PyObject* args) -{ - HANDLE handle; - - if (! PyArg_ParseTuple(args, ":Detach")) - return NULL; - - handle = self->handle; - - self->handle = INVALID_HANDLE_VALUE; - - /* note: return the current handle, as an integer */ - return HANDLE_TO_PYNUM(handle); -} - -static PyObject* -sp_handle_close(sp_handle_object* self, PyObject* args) -{ - if (! PyArg_ParseTuple(args, ":Close")) - return NULL; - - if (self->handle != INVALID_HANDLE_VALUE) { - CloseHandle(self->handle); - self->handle = INVALID_HANDLE_VALUE; - } - Py_INCREF(Py_None); - return Py_None; -} - -static void -sp_handle_dealloc(sp_handle_object* self) -{ - if (self->handle != INVALID_HANDLE_VALUE) - CloseHandle(self->handle); - PyObject_FREE(self); -} - -static PyMethodDef sp_handle_methods[] = { - {"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS}, - {"Close", (PyCFunction) sp_handle_close, METH_VARARGS}, - {NULL, NULL} -}; - -static PyObject* -sp_handle_as_int(sp_handle_object* self) -{ - return HANDLE_TO_PYNUM(self->handle); -} - -static PyNumberMethods sp_handle_as_number; - -static PyTypeObject sp_handle_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_subprocess_handle", sizeof(sp_handle_object), 0, - (destructor) sp_handle_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - &sp_handle_as_number, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - sp_handle_methods, /*tp_methods*/ -}; - -/* -------------------------------------------------------------------- */ -/* windows API functions */ - -PyDoc_STRVAR(GetStdHandle_doc, -"GetStdHandle(handle) -> integer\n\ -\n\ -Return a handle to the specified standard device\n\ -(STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\ -The integer associated with the handle object is returned."); - -static PyObject * -sp_GetStdHandle(PyObject* self, PyObject* args) -{ - HANDLE handle; - int std_handle; - - if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - handle = GetStdHandle((DWORD) std_handle); - Py_END_ALLOW_THREADS - - if (handle == INVALID_HANDLE_VALUE) - return PyErr_SetFromWindowsErr(GetLastError()); - - if (! handle) { - Py_INCREF(Py_None); - return Py_None; - } - - /* note: returns integer, not handle object */ - return HANDLE_TO_PYNUM(handle); -} - -PyDoc_STRVAR(GetCurrentProcess_doc, -"GetCurrentProcess() -> handle\n\ -\n\ -Return a handle object for the current process."); - -static PyObject * -sp_GetCurrentProcess(PyObject* self, PyObject* args) -{ - if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) - return NULL; - - return sp_handle_new(GetCurrentProcess()); -} - -PyDoc_STRVAR(DuplicateHandle_doc, -"DuplicateHandle(source_proc_handle, source_handle,\n\ - target_proc_handle, target_handle, access,\n\ - inherit[, options]) -> handle\n\ -\n\ -Return a duplicate handle object.\n\ -\n\ -The duplicate handle refers to the same object as the original\n\ -handle. Therefore, any changes to the object are reflected\n\ -through both handles."); - -static PyObject * -sp_DuplicateHandle(PyObject* self, PyObject* args) -{ - HANDLE target_handle; - BOOL result; - - HANDLE source_process_handle; - HANDLE source_handle; - HANDLE target_process_handle; - int desired_access; - int inherit_handle; - int options = 0; - - if (! PyArg_ParseTuple(args, - PY_HANDLE_PARAM PY_HANDLE_PARAM PY_HANDLE_PARAM - "ii|i:DuplicateHandle", - &source_process_handle, - &source_handle, - &target_process_handle, - &desired_access, - &inherit_handle, - &options)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - result = DuplicateHandle( - source_process_handle, - source_handle, - target_process_handle, - &target_handle, - desired_access, - inherit_handle, - options - ); - Py_END_ALLOW_THREADS - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - return sp_handle_new(target_handle); -} - -PyDoc_STRVAR(CreatePipe_doc, -"CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\ -\n\ -Create an anonymous pipe, and return handles to the read and\n\ -write ends of the pipe.\n\ -\n\ -pipe_attrs is ignored internally and can be None."); - -static PyObject * -sp_CreatePipe(PyObject* self, PyObject* args) -{ - HANDLE read_pipe; - HANDLE write_pipe; - BOOL result; - - PyObject* pipe_attributes; /* ignored */ - int size; - - if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - result = CreatePipe(&read_pipe, &write_pipe, NULL, size); - Py_END_ALLOW_THREADS - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - return Py_BuildValue( - "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe)); -} - -/* helpers for createprocess */ - -static int -getint(PyObject* obj, char* name) -{ - PyObject* value; - int ret; - - value = PyObject_GetAttrString(obj, name); - if (! value) { - PyErr_Clear(); /* FIXME: propagate error? */ - return 0; - } - ret = (int) PyLong_AsLong(value); - Py_DECREF(value); - return ret; -} - -static HANDLE -gethandle(PyObject* obj, char* name) -{ - sp_handle_object* value; - HANDLE ret; - - value = (sp_handle_object*) PyObject_GetAttrString(obj, name); - if (! value) { - PyErr_Clear(); /* FIXME: propagate error? */ - return NULL; - } - if (Py_TYPE(value) != &sp_handle_type) - ret = NULL; - else - ret = value->handle; - Py_DECREF(value); - return ret; -} - -static PyObject* -getenvironment(PyObject* environment) -{ - Py_ssize_t i, envsize, totalsize; - Py_UCS4 *buffer = NULL, *p, *end; - PyObject *keys, *values, *res; - - /* convert environment dictionary to windows enviroment string */ - if (! PyMapping_Check(environment)) { - PyErr_SetString( - PyExc_TypeError, "environment must be dictionary or None"); - return NULL; - } - - envsize = PyMapping_Length(environment); - - keys = PyMapping_Keys(environment); - values = PyMapping_Values(environment); - if (!keys || !values) - goto error; - - totalsize = 1; /* trailing null character */ - for (i = 0; i < envsize; i++) { - PyObject* key = PyList_GET_ITEM(keys, i); - PyObject* value = PyList_GET_ITEM(values, i); - - if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "environment can only contain strings"); - goto error; - } - totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ - totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ - } - - buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); - if (! buffer) - goto error; - p = buffer; - end = buffer + totalsize; - - for (i = 0; i < envsize; i++) { - PyObject* key = PyList_GET_ITEM(keys, i); - PyObject* value = PyList_GET_ITEM(values, i); - if (!PyUnicode_AsUCS4(key, p, end - p, 0)) - goto error; - p += PyUnicode_GET_LENGTH(key); - *p++ = '='; - if (!PyUnicode_AsUCS4(value, p, end - p, 0)) - goto error; - p += PyUnicode_GET_LENGTH(value); - *p++ = '\0'; - } - - /* add trailing null byte */ - *p++ = '\0'; - assert(p == end); - - Py_XDECREF(keys); - Py_XDECREF(values); - - res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer); - PyMem_Free(buffer); - return res; - - error: - PyMem_Free(buffer); - Py_XDECREF(keys); - Py_XDECREF(values); - return NULL; -} - -PyDoc_STRVAR(CreateProcess_doc, -"CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\ - inherit, flags, env_mapping, curdir,\n\ - startup_info) -> (proc_handle, thread_handle,\n\ - pid, tid)\n\ -\n\ -Create a new process and its primary thread. The return\n\ -value is a tuple of the process handle, thread handle,\n\ -process ID, and thread ID.\n\ -\n\ -proc_attrs and thread_attrs are ignored internally and can be None."); - -static PyObject * -sp_CreateProcess(PyObject* self, PyObject* args) -{ - BOOL result; - PROCESS_INFORMATION pi; - STARTUPINFOW si; - PyObject* environment; - wchar_t *wenvironment; - - wchar_t* application_name; - wchar_t* command_line; - PyObject* process_attributes; /* ignored */ - PyObject* thread_attributes; /* ignored */ - int inherit_handles; - int creation_flags; - PyObject* env_mapping; - wchar_t* current_directory; - PyObject* startup_info; - - if (! PyArg_ParseTuple(args, "ZZOOiiOZO:CreateProcess", - &application_name, - &command_line, - &process_attributes, - &thread_attributes, - &inherit_handles, - &creation_flags, - &env_mapping, - ¤t_directory, - &startup_info)) - return NULL; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - /* note: we only support a small subset of all SI attributes */ - si.dwFlags = getint(startup_info, "dwFlags"); - si.wShowWindow = getint(startup_info, "wShowWindow"); - si.hStdInput = gethandle(startup_info, "hStdInput"); - si.hStdOutput = gethandle(startup_info, "hStdOutput"); - si.hStdError = gethandle(startup_info, "hStdError"); - - if (PyErr_Occurred()) - return NULL; - - if (env_mapping != Py_None) { - environment = getenvironment(env_mapping); - if (! environment) - return NULL; - wenvironment = PyUnicode_AsUnicode(environment); - if (wenvironment == NULL) - { - Py_XDECREF(environment); - return NULL; - } - } - else { - environment = NULL; - wenvironment = NULL; - } - - Py_BEGIN_ALLOW_THREADS - result = CreateProcessW(application_name, - command_line, - NULL, - NULL, - inherit_handles, - creation_flags | CREATE_UNICODE_ENVIRONMENT, - wenvironment, - current_directory, - &si, - &pi); - Py_END_ALLOW_THREADS - - Py_XDECREF(environment); - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - return Py_BuildValue("NNii", - sp_handle_new(pi.hProcess), - sp_handle_new(pi.hThread), - pi.dwProcessId, - pi.dwThreadId); -} - -PyDoc_STRVAR(TerminateProcess_doc, -"TerminateProcess(handle, exit_code) -> None\n\ -\n\ -Terminate the specified process and all of its threads."); - -static PyObject * -sp_TerminateProcess(PyObject* self, PyObject* args) -{ - BOOL result; - - HANDLE process; - int exit_code; - if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess", - &process, &exit_code)) - return NULL; - - result = TerminateProcess(process, exit_code); - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(GetExitCodeProcess_doc, -"GetExitCodeProcess(handle) -> Exit code\n\ -\n\ -Return the termination status of the specified process."); - -static PyObject * -sp_GetExitCodeProcess(PyObject* self, PyObject* args) -{ - DWORD exit_code; - BOOL result; - - HANDLE process; - if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetExitCodeProcess", &process)) - return NULL; - - result = GetExitCodeProcess(process, &exit_code); - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - return PyLong_FromLong(exit_code); -} - -PyDoc_STRVAR(WaitForSingleObject_doc, -"WaitForSingleObject(handle, timeout) -> result\n\ -\n\ -Wait until the specified object is in the signaled state or\n\ -the time-out interval elapses. The timeout value is specified\n\ -in milliseconds."); - -static PyObject * -sp_WaitForSingleObject(PyObject* self, PyObject* args) -{ - DWORD result; - - HANDLE handle; - int milliseconds; - if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:WaitForSingleObject", - &handle, - &milliseconds)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - result = WaitForSingleObject(handle, (DWORD) milliseconds); - Py_END_ALLOW_THREADS - - if (result == WAIT_FAILED) - return PyErr_SetFromWindowsErr(GetLastError()); - - return PyLong_FromLong((int) result); -} - -PyDoc_STRVAR(GetVersion_doc, -"GetVersion() -> version\n\ -\n\ -Return the version number of the current operating system."); - -static PyObject * -sp_GetVersion(PyObject* self, PyObject* args) -{ - if (! PyArg_ParseTuple(args, ":GetVersion")) - return NULL; - - return PyLong_FromLong((int) GetVersion()); -} - -PyDoc_STRVAR(GetModuleFileName_doc, -"GetModuleFileName(module) -> path\n\ -\n\ -Return the fully-qualified path for the file that contains\n\ -the specified module. The module must have been loaded by the\n\ -current process.\n\ -\n\ -The module parameter should be a handle to the loaded module\n\ -whose path is being requested. If this parameter is 0, \n\ -GetModuleFileName retrieves the path of the executable file\n\ -of the current process."); - -static PyObject * -sp_GetModuleFileName(PyObject* self, PyObject* args) -{ - BOOL result; - HMODULE module; - WCHAR filename[MAX_PATH]; - - if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetModuleFileName", - &module)) - return NULL; - - result = GetModuleFileNameW(module, filename, MAX_PATH); - filename[MAX_PATH-1] = '\0'; - - if (! result) - return PyErr_SetFromWindowsErr(GetLastError()); - - return PyUnicode_FromWideChar(filename, wcslen(filename)); -} - -static PyMethodDef sp_functions[] = { - {"GetStdHandle", sp_GetStdHandle, METH_VARARGS, GetStdHandle_doc}, - {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS, - GetCurrentProcess_doc}, - {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS, - DuplicateHandle_doc}, - {"CreatePipe", sp_CreatePipe, METH_VARARGS, CreatePipe_doc}, - {"CreateProcess", sp_CreateProcess, METH_VARARGS, CreateProcess_doc}, - {"TerminateProcess", sp_TerminateProcess, METH_VARARGS, - TerminateProcess_doc}, - {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS, - GetExitCodeProcess_doc}, - {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS, - WaitForSingleObject_doc}, - {"GetVersion", sp_GetVersion, METH_VARARGS, GetVersion_doc}, - {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS, - GetModuleFileName_doc}, - {NULL, NULL} -}; - -/* -------------------------------------------------------------------- */ - -static void -defint(PyObject* d, const char* name, int value) -{ - PyObject* v = PyLong_FromLong((long) value); - if (v) { - PyDict_SetItemString(d, (char*) name, v); - Py_DECREF(v); - } -} - -static struct PyModuleDef _subprocessmodule = { - PyModuleDef_HEAD_INIT, - "_subprocess", - NULL, - -1, - sp_functions, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__subprocess() -{ - PyObject *d; - PyObject *m; - - /* patch up object descriptors */ - sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; - if (PyType_Ready(&sp_handle_type) < 0) - return NULL; - - m = PyModule_Create(&_subprocessmodule); - if (m == NULL) - return NULL; - d = PyModule_GetDict(m); - - /* constants */ - defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); - defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); - defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); - defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); - defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); - defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW); - defint(d, "SW_HIDE", SW_HIDE); - defint(d, "INFINITE", INFINITE); - defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); - defint(d, "WAIT_TIMEOUT", WAIT_TIMEOUT); - defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); - defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); - defint(d, "STILL_ACTIVE", STILL_ACTIVE); - - return m; -} diff --git a/PC/config.c b/PC/config.c index d055f9ae379..2d2141d5f36 100644 --- a/PC/config.c +++ b/PC/config.c @@ -56,7 +56,7 @@ extern PyObject* PyInit__codecs_iso2022(void); extern PyObject* PyInit__codecs_jp(void); extern PyObject* PyInit__codecs_kr(void); extern PyObject* PyInit__codecs_tw(void); -extern PyObject* PyInit__subprocess(void); +extern PyObject* PyInit__winapi(void); extern PyObject* PyInit__lsprof(void); extern PyObject* PyInit__ast(void); extern PyObject* PyInit__io(void); @@ -101,8 +101,8 @@ struct _inittab _PyImport_Inittab[] = { {"msvcrt", PyInit_msvcrt}, {"_locale", PyInit__locale}, #endif - /* XXX Should _subprocess go in a WIN32 block? not WIN64? */ - {"_subprocess", PyInit__subprocess}, + /* XXX Should _winapi go in a WIN32 block? not WIN64? */ + {"_winapi", PyInit__winapi}, {"_codecs", PyInit__codecs}, {"_weakref", PyInit__weakref}, diff --git a/PCbuild/_multiprocessing.vcproj b/PCbuild/_multiprocessing.vcproj index e9cd3a8101d..58238f82e79 100644 --- a/PCbuild/_multiprocessing.vcproj +++ b/PCbuild/_multiprocessing.vcproj @@ -534,10 +534,6 @@ RelativePath="..\Modules\_multiprocessing\semaphore.c" > - - diff --git a/PCbuild/pythoncore.vcproj b/PCbuild/pythoncore.vcproj index 0761f625cf8..1c322292589 100644 --- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -1054,6 +1054,10 @@ RelativePath="..\Modules\_weakref.c" > + + @@ -1678,10 +1682,6 @@ - - diff --git a/setup.py b/setup.py index d043ca8d5fc..f7a8a659751 100644 --- a/setup.py +++ b/setup.py @@ -1387,7 +1387,6 @@ class PyBuildExt(build_ext): if platform == 'win32': multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c', '_multiprocessing/semaphore.c', - '_multiprocessing/win32_functions.c' ] else: