cpython: f3706a9430da (original) (raw)
Mercurial > cpython
changeset 105739:f3706a9430da 3.6
Issue #19542: Fix bugs in WeakValueDictionary.setdefault() and WeakValueDictionary.pop() when a GC collection happens in another thread. Original patch and report by Armin Rigo. [#19542]
Antoine Pitrou solipsis@pitrou.net | |
---|---|
date | Mon, 19 Dec 2016 10:58:14 +0100 |
parents | 781c56168484(current diff)5a542a2bca08(diff) |
children | ac2715d04119 da958d01755a |
files | Lib/test/test_weakref.py Misc/NEWS |
diffstat | 3 files changed, 53 insertions(+), 5 deletions(-)[+] [-] Lib/test/test_weakref.py 41 Lib/weakref.py 13 Misc/NEWS 4 |
line wrap: on
line diff
--- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -6,6 +6,7 @@ import weakref import operator import contextlib import copy +import time from test import support from test.support import script_helper @@ -72,6 +73,29 @@ class TestBase(unittest.TestCase): self.cbcalled += 1 +@contextlib.contextmanager +def collect_in_thread(period=0.0001):
- """
- Ensure GC collections happen in a different thread, at a high frequency.
- """
- threading = support.import_module('threading')
- please_stop = False
- with support.disable_gc():
t = threading.Thread(target=collect)[](#l1.29)
t.start()[](#l1.30)
try:[](#l1.31)
yield[](#l1.32)
finally:[](#l1.33)
please_stop = True[](#l1.34)
t.join()[](#l1.35)
+ + class ReferencesTestCase(TestBase): def test_basic_ref(self): @@ -1636,6 +1660,23 @@ class MappingTestCase(TestBase): dict = weakref.WeakKeyDictionary() self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>')
- def test_threaded_weak_valued_setdefault(self):
d = weakref.WeakValueDictionary()[](#l1.46)
with collect_in_thread():[](#l1.47)
for i in range(100000):[](#l1.48)
x = d.setdefault(10, RefCycle())[](#l1.49)
self.assertIsNot(x, None) # we never put None in there
del x[](#l1.51)
- def test_threaded_weak_valued_pop(self):
d = weakref.WeakValueDictionary()[](#l1.54)
with collect_in_thread():[](#l1.55)
for i in range(100000):[](#l1.56)
d[10] = RefCycle()[](#l1.57)
x = d.pop(10, 10)[](#l1.58)
self.assertIsNot(x, None) # we never put None in there
+ + from test import mapping_tests class WeakValueDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
--- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -239,24 +239,27 @@ class WeakValueDictionary(collections.Mu try: o = self.data.pop(key)() except KeyError:
o = None[](#l2.7)
if o is None:[](#l2.8) if args:[](#l2.9) return args[0][](#l2.10)
raise[](#l2.11)
if o is None:[](#l2.12)
raise KeyError(key)[](#l2.13)
else:[](#l2.14)
raise KeyError(key)[](#l2.15) else:[](#l2.16) return o[](#l2.17)
def setdefault(self, key, default=None): try:
wr = self.data[key][](#l2.21)
o = self.data[key]()[](#l2.22) except KeyError:[](#l2.23)
o = None[](#l2.24)
if o is None:[](#l2.25) if self._pending_removals:[](#l2.26) self._commit_removals()[](#l2.27) self.data[key] = KeyedRef(default, self._remove, key)[](#l2.28) return default[](#l2.29) else:[](#l2.30)
return wr()[](#l2.31)
return o[](#l2.32)
def update(*args, **kwargs): if not args:
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Core and Builtins Library ------- +- Issue #19542: Fix bugs in WeakValueDictionary.setdefault() and