summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/multiprocessing.rst7
-rw-r--r--Lib/multiprocessing/connection.py7
-rw-r--r--Lib/multiprocessing/forking.py9
-rw-r--r--Lib/multiprocessing/util.py15
-rw-r--r--Lib/test/test_multiprocessing.py44
-rw-r--r--Misc/NEWS3
6 files changed, 42 insertions, 43 deletions
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
index bdc07f1..320e492 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -928,6 +928,12 @@ object -- see :ref:`multiprocessing-managers`.
.. note::
+ The :meth:`acquire` and :meth:`wait` methods of each of these types
+ treat negative timeouts as zero timeouts. This differs from
+ :mod:`threading` where, since version 3.2, the equivalent
+ :meth:`acquire` methods treat negative timeouts as infinite
+ timeouts.
+
On Mac OS X, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with
a timeout will emulate that function's behavior using a sleeping loop.
@@ -1899,6 +1905,7 @@ multiple connections at the same time.
those objects in *object_list* which are ready. If *timeout* is a
float then the call blocks for at most that many seconds. If
*timeout* is ``None`` then it will block for an unlimited period.
+ A negative timeout is equivalent to a zero timeout.
For both Unix and Windows, an object can appear in *object_list* if
it is
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
index acf43b1..56f375d 100644
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -23,8 +23,7 @@ import itertools
import _multiprocessing
from multiprocessing import current_process, AuthenticationError, BufferTooShort
-from multiprocessing.util import (
- get_temp_dir, Finalize, sub_debug, debug, _eintr_retry)
+from multiprocessing.util import get_temp_dir, Finalize, sub_debug, debug
from multiprocessing.forking import ForkingPickler
try:
import _winapi
@@ -323,8 +322,6 @@ if _winapi:
if (self._got_empty_message or
_winapi.PeekNamedPipe(self._handle)[0] != 0):
return True
- if timeout < 0:
- timeout = None
return bool(wait([self], timeout))
def _get_more_data(self, ov, maxsize):
@@ -402,8 +399,6 @@ class Connection(_ConnectionBase):
return self._recv(size)
def _poll(self, timeout):
- if timeout < 0.0:
- timeout = None
r = wait([self._handle], timeout)
return bool(r)
diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py
index ca03e95..2729afe 100644
--- a/Lib/multiprocessing/forking.py
+++ b/Lib/multiprocessing/forking.py
@@ -75,12 +75,9 @@ else:
#
if sys.platform != 'win32':
- import select
-
exit = os._exit
duplicate = os.dup
close = os.close
- _select = util._eintr_retry(select.select)
#
# We define a Popen class similar to the one from subprocess, but
@@ -130,10 +127,10 @@ if sys.platform != 'win32':
def wait(self, timeout=None):
if self.returncode is None:
if timeout is not None:
- r = _select([self.sentinel], [], [], timeout)[0]
- if not r:
+ from .connection import wait
+ if not wait([self.sentinel], timeout):
return None
- # This shouldn't block if select() returned successfully.
+ # This shouldn't block if wait() returned successfully.
return self.poll(os.WNOHANG if timeout == 0.0 else 0)
return self.returncode
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index da99063..9b6dac2 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -295,18 +295,3 @@ class ForkAwareLocal(threading.local):
register_after_fork(self, lambda obj : obj.__dict__.clear())
def __reduce__(self):
return type(self), ()
-
-
-#
-# Automatic retry after EINTR
-#
-
-def _eintr_retry(func):
- @functools.wraps(func)
- def wrapped(*args, **kwargs):
- while True:
- try:
- return func(*args, **kwargs)
- except InterruptedError:
- continue
- return wrapped
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
index a839917..d10d51b 100644
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -83,23 +83,13 @@ HAVE_GETVALUE = not getattr(_multiprocessing,
'HAVE_BROKEN_SEM_GETVALUE', False)
WIN32 = (sys.platform == "win32")
-if WIN32:
- from _winapi import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
- def wait_for_handle(handle, timeout):
- if timeout is None or timeout < 0.0:
- timeout = INFINITE
- else:
- timeout = int(1000 * timeout)
- return WaitForSingleObject(handle, timeout) == WAIT_OBJECT_0
-else:
- from select import select
- _select = util._eintr_retry(select)
+from multiprocessing.connection import wait
- def wait_for_handle(handle, timeout):
- if timeout is not None and timeout < 0.0:
- timeout = None
- return handle in _select([handle], [], [], timeout)[0]
+def wait_for_handle(handle, timeout):
+ if timeout is not None and timeout < 0.0:
+ timeout = None
+ return wait([handle], timeout)
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
@@ -291,9 +281,18 @@ class _TestProcess(BaseTestCase):
self.assertIn(p, self.active_children())
self.assertEqual(p.exitcode, None)
+ join = TimingWrapper(p.join)
+
+ self.assertEqual(join(0), None)
+ self.assertTimingAlmostEqual(join.elapsed, 0.0)
+ self.assertEqual(p.is_alive(), True)
+
+ self.assertEqual(join(-1), None)
+ self.assertTimingAlmostEqual(join.elapsed, 0.0)
+ self.assertEqual(p.is_alive(), True)
+
p.terminate()
- join = TimingWrapper(p.join)
self.assertEqual(join(), None)
self.assertTimingAlmostEqual(join.elapsed, 0.0)
@@ -1664,6 +1663,9 @@ class _TestConnection(BaseTestCase):
self.assertEqual(poll(), False)
self.assertTimingAlmostEqual(poll.elapsed, 0)
+ self.assertEqual(poll(-1), False)
+ self.assertTimingAlmostEqual(poll.elapsed, 0)
+
self.assertEqual(poll(TIMEOUT1), False)
self.assertTimingAlmostEqual(poll.elapsed, TIMEOUT1)
@@ -2785,6 +2787,16 @@ class TestWait(unittest.TestCase):
p.terminate()
p.join()
+ def test_neg_timeout(self):
+ from multiprocessing.connection import wait
+ a, b = multiprocessing.Pipe()
+ t = time.time()
+ res = wait([a], timeout=-1)
+ t = time.time() - t
+ self.assertEqual(res, [])
+ self.assertLess(t, 1)
+ a.close()
+ b.close()
#
# Issue 14151: Test invalid family on invalid environment
diff --git a/Misc/NEWS b/Misc/NEWS
index f383e91..d123c01 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,9 @@ Core and Builtins
Library
-------
+- Issue #14753: Make multiprocessing's handling of negative timeouts
+ the same as it was in Python 3.2.
+
- Issue #14583: Fix importlib bug when a package's __init__.py would first
import one of its modules then raise an error.