|
1 | 1 | import enum
|
2 | 2 | import unittest
|
| 3 | +from test import support |
3 | 4 | from test.support import import_helper
|
4 | 5 | from test.support import os_helper
|
| 6 | +from test.support import threading_helper |
5 | 7 |
|
6 | 8 | _testlimitedcapi = import_helper.import_module('_testlimitedcapi')
|
7 | 9 | _testcapi = import_helper.import_module('_testcapi')
|
| 10 | +_testinternalcapi = import_helper.import_module('_testinternalcapi') |
8 | 11 |
|
9 | 12 |
|
10 | 13 | class Constant(enum.IntEnum):
|
@@ -131,5 +134,48 @@ def test_ClearWeakRefsNoCallbacks_no_weakref_support(self):
|
131 | 134 | _testcapi.pyobject_clear_weakrefs_no_callbacks(obj)
|
132 | 135 |
|
133 | 136 |
|
| 137 | +class EnableDeferredRefcountingTest(unittest.TestCase): |
| 138 | + """Test PyUnstable_Object_EnableDeferredRefcount""" |
| 139 | + @support.requires_resource("cpu") |
| 140 | + def test_enable_deferred_refcount(self): |
| 141 | + from threading import Thread |
| 142 | + |
| 143 | + self.assertEqual(_testcapi.pyobject_enable_deferred_refcount("not tracked"), 0) |
| 144 | + foo = [] |
| 145 | + self.assertEqual(_testcapi.pyobject_enable_deferred_refcount(foo), int(support.Py_GIL_DISABLED)) |
| 146 | + |
| 147 | + # Make sure reference counting works on foo now |
| 148 | + self.assertEqual(foo, []) |
| 149 | + if support.Py_GIL_DISABLED: |
| 150 | + self.assertTrue(_testinternalcapi.has_deferred_refcount(foo)) |
| 151 | + |
| 152 | + # Make sure that PyUnstable_Object_EnableDeferredRefcount is thread safe |
| 153 | + def silly_func(obj): |
| 154 | + self.assertIn( |
| 155 | + _testcapi.pyobject_enable_deferred_refcount(obj), |
| 156 | + (0, 1) |
| 157 | + ) |
| 158 | + |
| 159 | + silly_list = [1, 2, 3] |
| 160 | + threads = [ |
| 161 | + Thread(target=silly_func, args=(silly_list,)) for _ in range(5) |
| 162 | + ] |
| 163 | + |
| 164 | + with threading_helper.catch_threading_exception() as cm: |
| 165 | + for t in threads: |
| 166 | + t.start() |
| 167 | + |
| 168 | + for i in range(10): |
| 169 | + silly_list.append(i) |
| 170 | + |
| 171 | + for t in threads: |
| 172 | + t.join() |
| 173 | + |
| 174 | + self.assertIsNone(cm.exc_value) |
| 175 | + |
| 176 | + if support.Py_GIL_DISABLED: |
| 177 | + self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list)) |
| 178 | + |
| 179 | + |
134 | 180 | if __name__ == "__main__":
|
135 | 181 | unittest.main()
|
0 commit comments