17f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
27f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# Module to allow connection and socket objects to be transferred
37f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# between processes
47f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
57f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# multiprocessing/reduction.py
67f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
779af245fb24a3608c341410ab9c782ce930401feR. David Murray# Copyright (c) 2006-2008, R Oudkerk
879af245fb24a3608c341410ab9c782ce930401feR. David Murray# All rights reserved.
979af245fb24a3608c341410ab9c782ce930401feR. David Murray#
1079af245fb24a3608c341410ab9c782ce930401feR. David Murray# Redistribution and use in source and binary forms, with or without
1179af245fb24a3608c341410ab9c782ce930401feR. David Murray# modification, are permitted provided that the following conditions
1279af245fb24a3608c341410ab9c782ce930401feR. David Murray# are met:
1379af245fb24a3608c341410ab9c782ce930401feR. David Murray#
1479af245fb24a3608c341410ab9c782ce930401feR. David Murray# 1. Redistributions of source code must retain the above copyright
1579af245fb24a3608c341410ab9c782ce930401feR. David Murray#    notice, this list of conditions and the following disclaimer.
1679af245fb24a3608c341410ab9c782ce930401feR. David Murray# 2. Redistributions in binary form must reproduce the above copyright
1779af245fb24a3608c341410ab9c782ce930401feR. David Murray#    notice, this list of conditions and the following disclaimer in the
1879af245fb24a3608c341410ab9c782ce930401feR. David Murray#    documentation and/or other materials provided with the distribution.
1979af245fb24a3608c341410ab9c782ce930401feR. David Murray# 3. Neither the name of author nor the names of any contributors may be
2079af245fb24a3608c341410ab9c782ce930401feR. David Murray#    used to endorse or promote products derived from this software
2179af245fb24a3608c341410ab9c782ce930401feR. David Murray#    without specific prior written permission.
2279af245fb24a3608c341410ab9c782ce930401feR. David Murray#
2379af245fb24a3608c341410ab9c782ce930401feR. David Murray# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
2479af245fb24a3608c341410ab9c782ce930401feR. David Murray# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2579af245fb24a3608c341410ab9c782ce930401feR. David Murray# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2679af245fb24a3608c341410ab9c782ce930401feR. David Murray# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2779af245fb24a3608c341410ab9c782ce930401feR. David Murray# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2879af245fb24a3608c341410ab9c782ce930401feR. David Murray# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2979af245fb24a3608c341410ab9c782ce930401feR. David Murray# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3079af245fb24a3608c341410ab9c782ce930401feR. David Murray# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3179af245fb24a3608c341410ab9c782ce930401feR. David Murray# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3279af245fb24a3608c341410ab9c782ce930401feR. David Murray# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3379af245fb24a3608c341410ab9c782ce930401feR. David Murray# SUCH DAMAGE.
347f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
357f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
367f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson__all__ = []
377f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
387f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonimport os
397f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonimport sys
407f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonimport socket
417f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonimport threading
427f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
437f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonimport _multiprocessing
447f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonfrom multiprocessing import current_process
4513e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse Nollerfrom multiprocessing.forking import Popen, duplicate, close, ForkingPickler
467f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonfrom multiprocessing.util import register_after_fork, debug, sub_debug
477f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonfrom multiprocessing.connection import Client, Listener
487f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
497f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
507f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
517f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
527f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
537f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
547f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonif not(sys.platform == 'win32' or hasattr(_multiprocessing, 'recvfd')):
557f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    raise ImportError('pickling of connections not supported')
567f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
577f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
587f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# Platform specific definitions
597f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
607f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
617f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonif sys.platform == 'win32':
627f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    import _subprocess
632f8c8f47c740cadee8c16e5e07657e4657f905ecJesse Noller    from _multiprocessing import win32
647f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
657f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def send_handle(conn, handle, destination_pid):
667f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        process_handle = win32.OpenProcess(
677f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            win32.PROCESS_ALL_ACCESS, False, destination_pid
687f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            )
697f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        try:
707f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            new_handle = duplicate(handle, process_handle)
717f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            conn.send(new_handle)
727f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        finally:
737f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            close(process_handle)
747f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
757f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def recv_handle(conn):
767f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return conn.recv()
777f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
787f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonelse:
797f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def send_handle(conn, handle, destination_pid):
807f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        _multiprocessing.sendfd(conn.fileno(), handle)
817f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
827f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def recv_handle(conn):
837f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return _multiprocessing.recvfd(conn.fileno())
847f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
857f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
867f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# Support for a per-process server thread which caches pickled handles
877f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
887f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
897f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson_cache = set()
907f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
917f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef _reset(obj):
927f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    global _lock, _listener, _cache
937f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    for h in _cache:
947f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        close(h)
957f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    _cache.clear()
967f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    _lock = threading.Lock()
977f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    _listener = None
987f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
997f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson_reset(None)
1007f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonregister_after_fork(_reset, _reset)
1017f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1027f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef _get_listener():
1037f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    global _listener
1047f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1057f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    if _listener is None:
1067f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        _lock.acquire()
1077f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        try:
1087f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            if _listener is None:
1097f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                debug('starting listener and thread for sending handles')
1105bc9f4c09c99eb701dbee83fb9e26eed558e474fJesse Noller                _listener = Listener(authkey=current_process().authkey)
1117f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                t = threading.Thread(target=_serve)
1125bc9f4c09c99eb701dbee83fb9e26eed558e474fJesse Noller                t.daemon = True
1137f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                t.start()
1147f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        finally:
1157f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            _lock.release()
1167f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1177f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return _listener
1187f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1197f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef _serve():
1207f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    from .util import is_exiting, sub_warning
1217f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1227f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    while 1:
1237f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        try:
1247f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            conn = _listener.accept()
1257f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            handle_wanted, destination_pid = conn.recv()
1267f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            _cache.remove(handle_wanted)
1277f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            send_handle(conn, handle_wanted, destination_pid)
1287f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            close(handle_wanted)
1297f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            conn.close()
1307f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        except:
1317f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            if not is_exiting():
1327f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                import traceback
1337f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                sub_warning(
1347f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                    'thread for sharing handles raised exception :\n' +
1357f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                    '-'*79 + '\n' + traceback.format_exc() + '-'*79
1367f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson                    )
1377f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1387f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
1397f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson# Functions to be used for pickling/unpickling objects with handles
1407f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
1417f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1427f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef reduce_handle(handle):
1437f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    if Popen.thread_is_spawning():
1447f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return (None, Popen.duplicate_for_child(handle), True)
1457f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    dup_handle = duplicate(handle)
1467f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    _cache.add(dup_handle)
1477f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    sub_debug('reducing handle %d', handle)
1487f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return (_get_listener().address, dup_handle, False)
1497f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1507f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef rebuild_handle(pickled_data):
1517f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    address, handle, inherited = pickled_data
1527f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    if inherited:
1537f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return handle
1547f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    sub_debug('rebuilding handle %d', handle)
1555bc9f4c09c99eb701dbee83fb9e26eed558e474fJesse Noller    conn = Client(address, authkey=current_process().authkey)
1567f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    conn.send((handle, os.getpid()))
1577f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    new_handle = recv_handle(conn)
1587f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    conn.close()
1597f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return new_handle
1607f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1617f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
16213e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse Noller# Register `_multiprocessing.Connection` with `ForkingPickler`
1637f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
1647f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1657f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef reduce_connection(conn):
1667f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    rh = reduce_handle(conn.fileno())
1677f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return rebuild_connection, (rh, conn.readable, conn.writable)
1687f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1697f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef rebuild_connection(reduced_handle, readable, writable):
1707f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    handle = rebuild_handle(reduced_handle)
1717f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return _multiprocessing.Connection(
1727f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        handle, readable=readable, writable=writable
1737f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        )
1747f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
17513e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse NollerForkingPickler.register(_multiprocessing.Connection, reduce_connection)
1767f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1777f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
17813e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse Noller# Register `socket.socket` with `ForkingPickler`
1797f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
1807f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1817f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef fromfd(fd, family, type_, proto=0):
1827f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    s = socket.fromfd(fd, family, type_, proto)
1837f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    if s.__class__ is not socket.socket:
1847f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        s = socket.socket(_sock=s)
1857f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return s
1867f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1877f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef reduce_socket(s):
1887f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    reduced_handle = reduce_handle(s.fileno())
1897f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return rebuild_socket, (reduced_handle, s.family, s.type, s.proto)
1907f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1917f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersondef rebuild_socket(reduced_handle, family, type_, proto):
1927f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    fd = rebuild_handle(reduced_handle)
1937f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    _sock = fromfd(fd, family, type_, proto)
1947f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    close(fd)
1957f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    return _sock
1967f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
19713e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse NollerForkingPickler.register(socket.socket, reduce_socket)
1987f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
1997f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
20013e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse Noller# Register `_multiprocessing.PipeConnection` with `ForkingPickler`
2017f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson#
2027f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
2037f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Petersonif sys.platform == 'win32':
2047f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
2057f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def reduce_pipe_connection(conn):
2067f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        rh = reduce_handle(conn.fileno())
2077f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return rebuild_pipe_connection, (rh, conn.readable, conn.writable)
2087f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
2097f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson    def rebuild_pipe_connection(reduced_handle, readable, writable):
2107f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        handle = rebuild_handle(reduced_handle)
2117f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson        return _multiprocessing.PipeConnection(
2127f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            handle, readable=readable, writable=writable
2137f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson            )
2147f03ea77bf43257789469b5cbc16982eb0a63b0fBenjamin Peterson
21513e9d582fd55c3f680cbe9d3d4c219722a484d92Jesse Noller    ForkingPickler.register(_multiprocessing.PipeConnection, reduce_pipe_connection)
216