xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/asyncio/windows_utils.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Various Windows specific bits and pieces."""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerimport sys
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Workerif sys.platform != 'win32':  # pragma: no cover
6*cda5da8dSAndroid Build Coastguard Worker    raise ImportError('win32 only')
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Workerimport _winapi
9*cda5da8dSAndroid Build Coastguard Workerimport itertools
10*cda5da8dSAndroid Build Coastguard Workerimport msvcrt
11*cda5da8dSAndroid Build Coastguard Workerimport os
12*cda5da8dSAndroid Build Coastguard Workerimport subprocess
13*cda5da8dSAndroid Build Coastguard Workerimport tempfile
14*cda5da8dSAndroid Build Coastguard Workerimport warnings
15*cda5da8dSAndroid Build Coastguard Worker
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker__all__ = 'pipe', 'Popen', 'PIPE', 'PipeHandle'
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker
20*cda5da8dSAndroid Build Coastguard Worker# Constants/globals
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard WorkerBUFSIZE = 8192
24*cda5da8dSAndroid Build Coastguard WorkerPIPE = subprocess.PIPE
25*cda5da8dSAndroid Build Coastguard WorkerSTDOUT = subprocess.STDOUT
26*cda5da8dSAndroid Build Coastguard Worker_mmap_counter = itertools.count()
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker# Replacement for os.pipe() using handles instead of fds
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Workerdef pipe(*, duplex=False, overlapped=(True, True), bufsize=BUFSIZE):
33*cda5da8dSAndroid Build Coastguard Worker    """Like os.pipe() but with overlapped support and using handles not fds."""
34*cda5da8dSAndroid Build Coastguard Worker    address = tempfile.mktemp(
35*cda5da8dSAndroid Build Coastguard Worker        prefix=r'\\.\pipe\python-pipe-{:d}-{:d}-'.format(
36*cda5da8dSAndroid Build Coastguard Worker            os.getpid(), next(_mmap_counter)))
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Worker    if duplex:
39*cda5da8dSAndroid Build Coastguard Worker        openmode = _winapi.PIPE_ACCESS_DUPLEX
40*cda5da8dSAndroid Build Coastguard Worker        access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
41*cda5da8dSAndroid Build Coastguard Worker        obsize, ibsize = bufsize, bufsize
42*cda5da8dSAndroid Build Coastguard Worker    else:
43*cda5da8dSAndroid Build Coastguard Worker        openmode = _winapi.PIPE_ACCESS_INBOUND
44*cda5da8dSAndroid Build Coastguard Worker        access = _winapi.GENERIC_WRITE
45*cda5da8dSAndroid Build Coastguard Worker        obsize, ibsize = 0, bufsize
46*cda5da8dSAndroid Build Coastguard Worker
47*cda5da8dSAndroid Build Coastguard Worker    openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Worker    if overlapped[0]:
50*cda5da8dSAndroid Build Coastguard Worker        openmode |= _winapi.FILE_FLAG_OVERLAPPED
51*cda5da8dSAndroid Build Coastguard Worker
52*cda5da8dSAndroid Build Coastguard Worker    if overlapped[1]:
53*cda5da8dSAndroid Build Coastguard Worker        flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED
54*cda5da8dSAndroid Build Coastguard Worker    else:
55*cda5da8dSAndroid Build Coastguard Worker        flags_and_attribs = 0
56*cda5da8dSAndroid Build Coastguard Worker
57*cda5da8dSAndroid Build Coastguard Worker    h1 = h2 = None
58*cda5da8dSAndroid Build Coastguard Worker    try:
59*cda5da8dSAndroid Build Coastguard Worker        h1 = _winapi.CreateNamedPipe(
60*cda5da8dSAndroid Build Coastguard Worker            address, openmode, _winapi.PIPE_WAIT,
61*cda5da8dSAndroid Build Coastguard Worker            1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
62*cda5da8dSAndroid Build Coastguard Worker
63*cda5da8dSAndroid Build Coastguard Worker        h2 = _winapi.CreateFile(
64*cda5da8dSAndroid Build Coastguard Worker            address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
65*cda5da8dSAndroid Build Coastguard Worker            flags_and_attribs, _winapi.NULL)
66*cda5da8dSAndroid Build Coastguard Worker
67*cda5da8dSAndroid Build Coastguard Worker        ov = _winapi.ConnectNamedPipe(h1, overlapped=True)
68*cda5da8dSAndroid Build Coastguard Worker        ov.GetOverlappedResult(True)
69*cda5da8dSAndroid Build Coastguard Worker        return h1, h2
70*cda5da8dSAndroid Build Coastguard Worker    except:
71*cda5da8dSAndroid Build Coastguard Worker        if h1 is not None:
72*cda5da8dSAndroid Build Coastguard Worker            _winapi.CloseHandle(h1)
73*cda5da8dSAndroid Build Coastguard Worker        if h2 is not None:
74*cda5da8dSAndroid Build Coastguard Worker            _winapi.CloseHandle(h2)
75*cda5da8dSAndroid Build Coastguard Worker        raise
76*cda5da8dSAndroid Build Coastguard Worker
77*cda5da8dSAndroid Build Coastguard Worker
78*cda5da8dSAndroid Build Coastguard Worker# Wrapper for a pipe handle
79*cda5da8dSAndroid Build Coastguard Worker
80*cda5da8dSAndroid Build Coastguard Worker
81*cda5da8dSAndroid Build Coastguard Workerclass PipeHandle:
82*cda5da8dSAndroid Build Coastguard Worker    """Wrapper for an overlapped pipe handle which is vaguely file-object like.
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Worker    The IOCP event loop can use these instead of socket objects.
85*cda5da8dSAndroid Build Coastguard Worker    """
86*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, handle):
87*cda5da8dSAndroid Build Coastguard Worker        self._handle = handle
88*cda5da8dSAndroid Build Coastguard Worker
89*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
90*cda5da8dSAndroid Build Coastguard Worker        if self._handle is not None:
91*cda5da8dSAndroid Build Coastguard Worker            handle = f'handle={self._handle!r}'
92*cda5da8dSAndroid Build Coastguard Worker        else:
93*cda5da8dSAndroid Build Coastguard Worker            handle = 'closed'
94*cda5da8dSAndroid Build Coastguard Worker        return f'<{self.__class__.__name__} {handle}>'
95*cda5da8dSAndroid Build Coastguard Worker
96*cda5da8dSAndroid Build Coastguard Worker    @property
97*cda5da8dSAndroid Build Coastguard Worker    def handle(self):
98*cda5da8dSAndroid Build Coastguard Worker        return self._handle
99*cda5da8dSAndroid Build Coastguard Worker
100*cda5da8dSAndroid Build Coastguard Worker    def fileno(self):
101*cda5da8dSAndroid Build Coastguard Worker        if self._handle is None:
102*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("I/O operation on closed pipe")
103*cda5da8dSAndroid Build Coastguard Worker        return self._handle
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Worker    def close(self, *, CloseHandle=_winapi.CloseHandle):
106*cda5da8dSAndroid Build Coastguard Worker        if self._handle is not None:
107*cda5da8dSAndroid Build Coastguard Worker            CloseHandle(self._handle)
108*cda5da8dSAndroid Build Coastguard Worker            self._handle = None
109*cda5da8dSAndroid Build Coastguard Worker
110*cda5da8dSAndroid Build Coastguard Worker    def __del__(self, _warn=warnings.warn):
111*cda5da8dSAndroid Build Coastguard Worker        if self._handle is not None:
112*cda5da8dSAndroid Build Coastguard Worker            _warn(f"unclosed {self!r}", ResourceWarning, source=self)
113*cda5da8dSAndroid Build Coastguard Worker            self.close()
114*cda5da8dSAndroid Build Coastguard Worker
115*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
116*cda5da8dSAndroid Build Coastguard Worker        return self
117*cda5da8dSAndroid Build Coastguard Worker
118*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, t, v, tb):
119*cda5da8dSAndroid Build Coastguard Worker        self.close()
120*cda5da8dSAndroid Build Coastguard Worker
121*cda5da8dSAndroid Build Coastguard Worker
122*cda5da8dSAndroid Build Coastguard Worker# Replacement for subprocess.Popen using overlapped pipe handles
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker
125*cda5da8dSAndroid Build Coastguard Workerclass Popen(subprocess.Popen):
126*cda5da8dSAndroid Build Coastguard Worker    """Replacement for subprocess.Popen using overlapped pipe handles.
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker    The stdin, stdout, stderr are None or instances of PipeHandle.
129*cda5da8dSAndroid Build Coastguard Worker    """
130*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, args, stdin=None, stdout=None, stderr=None, **kwds):
131*cda5da8dSAndroid Build Coastguard Worker        assert not kwds.get('universal_newlines')
132*cda5da8dSAndroid Build Coastguard Worker        assert kwds.get('bufsize', 0) == 0
133*cda5da8dSAndroid Build Coastguard Worker        stdin_rfd = stdout_wfd = stderr_wfd = None
134*cda5da8dSAndroid Build Coastguard Worker        stdin_wh = stdout_rh = stderr_rh = None
135*cda5da8dSAndroid Build Coastguard Worker        if stdin == PIPE:
136*cda5da8dSAndroid Build Coastguard Worker            stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True)
137*cda5da8dSAndroid Build Coastguard Worker            stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY)
138*cda5da8dSAndroid Build Coastguard Worker        else:
139*cda5da8dSAndroid Build Coastguard Worker            stdin_rfd = stdin
140*cda5da8dSAndroid Build Coastguard Worker        if stdout == PIPE:
141*cda5da8dSAndroid Build Coastguard Worker            stdout_rh, stdout_wh = pipe(overlapped=(True, False))
142*cda5da8dSAndroid Build Coastguard Worker            stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0)
143*cda5da8dSAndroid Build Coastguard Worker        else:
144*cda5da8dSAndroid Build Coastguard Worker            stdout_wfd = stdout
145*cda5da8dSAndroid Build Coastguard Worker        if stderr == PIPE:
146*cda5da8dSAndroid Build Coastguard Worker            stderr_rh, stderr_wh = pipe(overlapped=(True, False))
147*cda5da8dSAndroid Build Coastguard Worker            stderr_wfd = msvcrt.open_osfhandle(stderr_wh, 0)
148*cda5da8dSAndroid Build Coastguard Worker        elif stderr == STDOUT:
149*cda5da8dSAndroid Build Coastguard Worker            stderr_wfd = stdout_wfd
150*cda5da8dSAndroid Build Coastguard Worker        else:
151*cda5da8dSAndroid Build Coastguard Worker            stderr_wfd = stderr
152*cda5da8dSAndroid Build Coastguard Worker        try:
153*cda5da8dSAndroid Build Coastguard Worker            super().__init__(args, stdin=stdin_rfd, stdout=stdout_wfd,
154*cda5da8dSAndroid Build Coastguard Worker                             stderr=stderr_wfd, **kwds)
155*cda5da8dSAndroid Build Coastguard Worker        except:
156*cda5da8dSAndroid Build Coastguard Worker            for h in (stdin_wh, stdout_rh, stderr_rh):
157*cda5da8dSAndroid Build Coastguard Worker                if h is not None:
158*cda5da8dSAndroid Build Coastguard Worker                    _winapi.CloseHandle(h)
159*cda5da8dSAndroid Build Coastguard Worker            raise
160*cda5da8dSAndroid Build Coastguard Worker        else:
161*cda5da8dSAndroid Build Coastguard Worker            if stdin_wh is not None:
162*cda5da8dSAndroid Build Coastguard Worker                self.stdin = PipeHandle(stdin_wh)
163*cda5da8dSAndroid Build Coastguard Worker            if stdout_rh is not None:
164*cda5da8dSAndroid Build Coastguard Worker                self.stdout = PipeHandle(stdout_rh)
165*cda5da8dSAndroid Build Coastguard Worker            if stderr_rh is not None:
166*cda5da8dSAndroid Build Coastguard Worker                self.stderr = PipeHandle(stderr_rh)
167*cda5da8dSAndroid Build Coastguard Worker        finally:
168*cda5da8dSAndroid Build Coastguard Worker            if stdin == PIPE:
169*cda5da8dSAndroid Build Coastguard Worker                os.close(stdin_rfd)
170*cda5da8dSAndroid Build Coastguard Worker            if stdout == PIPE:
171*cda5da8dSAndroid Build Coastguard Worker                os.close(stdout_wfd)
172*cda5da8dSAndroid Build Coastguard Worker            if stderr == PIPE:
173*cda5da8dSAndroid Build Coastguard Worker                os.close(stderr_wfd)
174