@@ -4,8 +4,10 @@
44fromconcurrent.futuresimportThreadPoolExecutor
55fromthreadingimportBarrier, Thread
66fromunittestimportTestCase
7+importsys
8+fromtest.supportimportimport_helper, threading_helper
798-fromtest.supportimportthreading_helper
10+_testinternalcapi=import_helper.import_module("_testinternalcapi")
91110121113@@ -84,6 +86,24 @@ def reader_func():
84868587self.run_one(writer_func, reader_func)
868889+deftest_attr_cache_mortal(self):
90+classC:
91+x=object()
92+93+classD(C):
94+pass
95+96+defwriter_func():
97+for_inrange(3000):
98+C.x=object()
99+100+defreader_func():
101+for_inrange(3000):
102+C.x
103+D.x
104+105+self.run_one(writer_func, reader_func)
106+87107deftest___class___modification(self):
88108loops=200
89109@@ -160,6 +180,51 @@ def reader():
160180161181self.run_one(writer, reader)
162182183+deftest_per_type_cache_concurrent_reads(self):
184+classC:
185+pass
186+187+names= [sys.intern(f"attr_{i}") foriinrange(
188+_testinternalcapi._Py_TYPECACHE_MINSIZE*4)]
189+fornameinnames:
190+setattr(C, name, name)
191+# Prime the cache.
192+fornameinnames:
193+getattr(C, name)
194+195+lookup=_testinternalcapi.type_cache_lookup
196+197+defreader():
198+for_inrange(500):
199+fornameinnames:
200+hit, value, _=lookup(C, name)
201+self.assertEqual(hit, 1, name)
202+self.assertEqual(value, name)
203+204+threading_helper.run_concurrently(reader, nthreads=NTHREADS)
205+206+deftest_per_type_cache_concurrent_invalidate(self):
207+classC:
208+x="value"
209+210+# Prime the cache.
211+C.x
212+hit, value, version=_testinternalcapi.type_cache_lookup(C, "x")
213+self.assertEqual(hit, 1)
214+self.assertIs(value, "value")
215+self.assertGreater(version, 0)
216+217+defreader():
218+for_inrange(10_000):
219+self.assertIs(C.x, "value")
220+221+definvalidator():
222+for_inrange(10_000):
223+_testinternalcapi.type_cache_invalidate(C)
224+225+workers= [invalidator] + [reader] * (NTHREADS-1)
226+threading_helper.run_concurrently(workers)
227+163228deftest_race_type_attr_added(self):
164229NROUNDS=50
165230NSTOPPERS=4