check([iter_next] + [iter_reduce] * 10, iter(ba)) # for tsan
check([iter_next] + [iter_setstate] * 10, iter(ba)) # for tsan
+ @unittest.skipUnless(support.Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled')
+ @threading_helper.reap_threads
+ @threading_helper.requires_working_threading()
+ def test_free_threading_bytearray_resize(self):
+ def resize_stress(ba):
+ for _ in range(1000):
+ try:
+ ba.resize(1000)
+ ba.resize(1)
+ except (BufferError, ValueError):
+ pass
+
+ ba = bytearray(100)
+ threads = [threading.Thread(target=resize_stress, args=(ba,)) for _ in range(4)]
+ with threading_helper.start_threads(threads):
+ pass
if __name__ == "__main__":
unittest.main()
--- /dev/null
+Make :meth:`bytearray.resize` thread-safe in the free-threaded build by
+using a critical section and calling the lock-held variant of the resize
+function.
/*[clinic input]
+@critical_section
bytearray.resize
size: Py_ssize_t
New size to resize to.
static PyObject *
bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size)
-/*[clinic end generated code: output=f73524922990b2d9 input=6c9a260ca7f72071]*/
+/*[clinic end generated code: output=f73524922990b2d9 input=116046316a2b5cfc]*/
{
Py_ssize_t start_size = PyByteArray_GET_SIZE(self);
- int result = PyByteArray_Resize((PyObject *)self, size);
+ int result = bytearray_resize_lock_held((PyObject *)self, size);
if (result < 0) {
return NULL;
}
}
size = ival;
}
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = bytearray_resize_impl((PyByteArrayObject *)self, size);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
{
return bytearray_sizeof_impl((PyByteArrayObject *)self);
}
-/*[clinic end generated code: output=5eddefde2a001ceb input=a9049054013a1b77]*/
+/*[clinic end generated code: output=2d76ef023928424f input=a9049054013a1b77]*/