self.run_one(writer, reader)
+ def test_bases_change(self):
+ class BaseA:
+ pass
+
+ class Derived(BaseA):
+ pass
+
+ def writer():
+ for _ in range(1000):
+ class BaseB:
+ pass
+ Derived.__bases__ = (BaseB,)
+
+ def reader():
+ for _ in range(1000):
+ Derived.__base__
+
+ self.run_one(writer, reader)
+
def run_one(self, writer_func, reader_func):
barrier = threading.Barrier(NTHREADS)
#define types_world_is_stopped() 1
#define types_stop_world()
#define types_start_world()
+#define type_lock_prevent_release()
+#define type_lock_allow_release()
#endif
assert(old_bases != NULL);
PyTypeObject *old_base = type->tp_base;
+ type_lock_prevent_release();
+ types_stop_world();
set_tp_bases(type, Py_NewRef(new_bases), 0);
type->tp_base = (PyTypeObject *)Py_NewRef(best_base);
+ types_start_world();
+ type_lock_allow_release();
PyObject *temp = PyList_New(0);
if (temp == NULL) {
if (lookup_tp_bases(type) == new_bases) {
assert(type->tp_base == best_base);
+ type_lock_prevent_release();
+ types_stop_world();
set_tp_bases(type, old_bases, 0);
type->tp_base = old_base;
+ types_start_world();
+ type_lock_allow_release();
Py_DECREF(new_bases);
Py_DECREF(best_base);
# PyObject_Realloc internally does memcpy which isn't atomic so can race
# with non-locking reads. See #132070
race:PyObject_Realloc
-
-# gh-133467. Some of these could be hard to trigger.
-race_top:set_tp_bases
-race_top:type_set_bases_unlocked