This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients dgrunwald, eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Date 2021-01-20.23:48:39
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1611186519.48.0.536668657473.issue42968@roundup.psfhosted.org>
In-reply-to
Content
I'm not fond of the way reduction.DupHandle() expects the receiving process to steal the duplicated handle. I'd prefer using the resource_sharer module, like reduction.DupFd() does in POSIX. Except spawning is a special case, for which reduction.DupHandle() can take advantage of the duplicate_for_child() method of the popen_spawn_win32.Popen instance.

With the resource sharer, the handle still needs to be duplicated in the sending process. But an important difference is the resource_sharer.stop() method, which at least allows closing any handles that no longer need to be shared.

---

Proposed Changes (untested)

resource_sharer.py:

    class DupHandle(object):
        '''Wrapper for a handle that can be used at any time.'''
        def __init__(self, handle):
            dh = reduction.duplicate(handle)
            def send(conn, pid):
                reduction.send_handle(conn, dh, pid)
            def close():
                _winapi.CloseHandle(dh)
            self._id = _resource_sharer.register(send, close)

        def detach(self):
            '''Get the handle. This should only be called once.'''
            with _resource_sharer.get_connection(self._id) as conn:
                return reduction.recv_handle(conn)


reduction.py:

    def send_handle(conn, handle, destination_pid):
        '''Send a handle over a local connection.'''
        proc = _winapi.OpenProcess(_winapi.PROCESS_DUP_HANDLE, False,
            destination_pid)
        try:
            dh = duplicate(handle, proc)
            conn.send(dh)
        finally:
            _winapi.CloseHandle(proc)

    def recv_handle(conn):
        '''Receive a handle over a local connection.'''
        return conn.recv()

    class _DupHandle:
        def __init__(self, handle):
            self.handle = handle
        def detach(self):
            return self.handle

    def DupHandle(handle):
        '''Return a wrapper for a handle.'''
        popen_obj = context.get_spawning_popen()
        if popen_obj is not None:
            return _DupHandle(popen_obj.duplicate_for_child(handle))
        from . import resource_sharer
        return resource_sharer.DupHandle(handle)


connection.py:

    def reduce_pipe_connection(conn):
        dh = reduction.DupHandle(conn.fileno())
        return rebuild_pipe_connection, (dh, conn.readable, conn.writable)

    def rebuild_pipe_connection(dh, readable, writable):
        return PipeConnection(dh.detach(), readable, writable)

    reduction.register(PipeConnection, reduce_pipe_connection)
History
Date User Action Args
2021-01-20 23:48:39eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, dgrunwald
2021-01-20 23:48:39eryksunsetmessageid: <1611186519.48.0.536668657473.issue42968@roundup.psfhosted.org>
2021-01-20 23:48:39eryksunlinkissue42968 messages
2021-01-20 23:48:39eryksuncreate