summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Oudkerk <shibturn@gmail.com>2013-04-17 19:58:00 (GMT)
committerRichard Oudkerk <shibturn@gmail.com>2013-04-17 19:58:00 (GMT)
commit409c31390f839debb2f05cef691e8b59e52bd524 (patch)
tree49a505458425a31be4c08e22c38c8c56c17d8992
parentb38897fc91c7f4b80bc2025ade219674d7b78bf3 (diff)
downloadcpython-409c31390f839debb2f05cef691e8b59e52bd524.zip
cpython-409c31390f839debb2f05cef691e8b59e52bd524.tar.gz
cpython-409c31390f839debb2f05cef691e8b59e52bd524.tar.bz2
Issue #17555: Fix ForkAwareThreadLock so that size of after fork
registry does not grow exponentially with generation of process.
-rw-r--r--Lib/multiprocessing/util.py5
-rw-r--r--Lib/test/test_multiprocessing.py32
-rw-r--r--Misc/NEWS3
3 files changed, 38 insertions, 2 deletions
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index 72385a8..f5862b4 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -322,10 +322,13 @@ atexit.register(_exit_function)
class ForkAwareThreadLock(object):
def __init__(self):
+ self._reset()
+ register_after_fork(self, ForkAwareThreadLock._reset)
+
+ def _reset(self):
self._lock = threading.Lock()
self.acquire = self._lock.acquire
self.release = self._lock.release
- register_after_fork(self, ForkAwareThreadLock.__init__)
class ForkAwareLocal(threading.local):
def __init__(self):
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
index 14ec61c..9b3e180 100644
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -3432,12 +3432,42 @@ class TestNoForkBomb(unittest.TestCase):
self.assertEqual('', err.decode('ascii'))
#
+# Issue #17555: ForkAwareThreadLock
+#
+
+class TestForkAwareThreadLock(unittest.TestCase):
+ # We recurisvely start processes. Issue #17555 meant that the
+ # after fork registry would get duplicate entries for the same
+ # lock. The size of the registry at generation n was ~2**n.
+
+ @classmethod
+ def child(cls, n, conn):
+ if n > 1:
+ p = multiprocessing.Process(target=cls.child, args=(n-1, conn))
+ p.start()
+ p.join()
+ else:
+ conn.send(len(util._afterfork_registry))
+ conn.close()
+
+ def test_lock(self):
+ r, w = multiprocessing.Pipe(False)
+ l = util.ForkAwareThreadLock()
+ old_size = len(util._afterfork_registry)
+ p = multiprocessing.Process(target=self.child, args=(5, w))
+ p.start()
+ new_size = r.recv()
+ p.join()
+ self.assertLessEqual(new_size, old_size)
+
+#
#
#
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
TestStdinBadfiledescriptor, TestWait, TestInvalidFamily,
- TestFlags, TestTimeouts, TestNoForkBomb]
+ TestFlags, TestTimeouts, TestNoForkBomb,
+ TestForkAwareThreadLock]
#
#
diff --git a/Misc/NEWS b/Misc/NEWS
index be59be0..5a8c0b9 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,9 @@ Core and Builtins
Library
-------
+- Issue #17555: Fix ForkAwareThreadLock so that size of after fork
+ registry does not grow exponentially with generation of process.
+
- Issue #17707: multiprocessing.Queue's get() method does not block for short
timeouts.