Skip to content

[3.7]bpo-39850: Add support for abstract sockets in multiprocessing (GH-18866) #18877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Lib/multiprocessing/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def address_type(address):
return 'AF_INET'
elif type(address) is str and address.startswith('\\\\'):
return 'AF_PIPE'
elif type(address) is str:
elif type(address) is str or util.is_abstract_socket_namespace(address):
return 'AF_UNIX'
else:
raise ValueError('address type of %r unrecognized' % address)
Expand Down Expand Up @@ -587,7 +587,8 @@ def __init__(self, address, family, backlog=1):
self._family = family
self._last_accepted = None

if family == 'AF_UNIX':
if family == 'AF_UNIX' and not util.is_abstract_socket_namespace(address):
# Linux abstract socket namespaces do not need to be explicitly unlinked
self._unlink = util.Finalize(
self, os.unlink, args=(address,), exitpriority=0
)
Expand Down
3 changes: 2 additions & 1 deletion Lib/multiprocessing/forkserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ def ensure_running(self):
with socket.socket(socket.AF_UNIX) as listener:
address = connection.arbitrary_address('AF_UNIX')
listener.bind(address)
os.chmod(address, 0o600)
if not util.is_abstract_socket_namespace(address):
os.chmod(address, 0o600)
listener.listen()

# all client processes own the write end of the "alive" pipe;
Expand Down
23 changes: 23 additions & 0 deletions Lib/multiprocessing/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ def log_to_stderr(level=None):
_log_to_stderr = True
return _logger


# Abstract socket support

def _platform_supports_abstract_sockets():
if sys.platform == "linux":
return True
if hasattr(sys, 'getandroidapilevel'):
return True
return False


def is_abstract_socket_namespace(address):
if not address:
return False
if isinstance(address, bytes):
return address[0] == 0
elif isinstance(address, str):
return address[0] == "\0"
raise TypeError('address type of {address!r} unrecognized')


abstract_sockets_supported = _platform_supports_abstract_sockets()

#
# Function returning a temp directory which will be removed on exit
#
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3140,6 +3140,19 @@ def test_context(self):
if self.TYPE == 'processes':
self.assertRaises(OSError, l.accept)

@unittest.skipUnless(util.abstract_sockets_supported,
"test needs abstract socket support")
def test_abstract_socket(self):
with self.connection.Listener("\0something") as listener:
with self.connection.Client(listener.address) as client:
with listener.accept() as d:
client.send(1729)
self.assertEqual(d.recv(), 1729)

if self.TYPE == 'processes':
self.assertRaises(OSError, listener.accept)


class _TestListenerClient(BaseTestCase):

ALLOWED_TYPES = ('processes', 'threads')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:mod:`multiprocessing` now supports abstract socket addresses (if abstract sockets
are supported in the running platform). Patch by Pablo Galindo.