https://github.com/python/cpython/commit/8ba0d7bbc295781bf27902380521db97a272c442
commit: 8ba0d7bbc295781bf27902380521db97a272c442
branch: main
author: Tomasz Pytel <tompy...@gmail.com>
committer: kumaraditya303 <kumaradi...@python.org>
date: 2025-02-27T14:00:14Z
summary:

gh-128942: make `array` module thread safe (#128943)

Co-authored-by: Kumar Aditya <kumaradi...@python.org>

files:
A Misc/NEWS.d/next/Library/2025-01-17-13-53-32.gh-issue-128942.DxzaIg.rst
M Lib/test/test_array.py
M Modules/arraymodule.c
M Modules/clinic/arraymodule.c.h

diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 58ea89c4fac833..bc3eeef8000190 100755
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -3,16 +3,21 @@
 """
 
 import collections.abc
+import io
 import unittest
 from test import support
 from test.support import import_helper
 from test.support import os_helper
+from test.support import threading_helper
 from test.support import _2G
 import weakref
 import pickle
 import operator
+import random
 import struct
 import sys
+import sysconfig
+import threading
 import warnings
 
 import array
@@ -1673,5 +1678,266 @@ def test_gh_128961(self):
         self.assertRaises(StopIteration, next, it)
 
 
+class FreeThreadingTest(unittest.TestCase):
+    # Test pretty much everything that can break under free-threading.
+    # Non-deterministic, but at least one of these things will fail if
+    # array module is not free-thread safe.
+
+    @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(self):
+        def pop1(b, a):  # MODIFIES!
+            b.wait()
+            try: a.pop()
+            except IndexError: pass
+
+        def append1(b, a):  # MODIFIES!
+            b.wait()
+            a.append(2)
+
+        def insert1(b, a):  # MODIFIES!
+            b.wait()
+            a.insert(0, 2)
+
+        def extend(b, a):  # MODIFIES!
+            c = array.array('i', [2])
+            b.wait()
+            a.extend(c)
+
+        def extend2(b, a, c):  # MODIFIES!
+            b.wait()
+            a.extend(c)
+
+        def inplace_concat(b, a):  # MODIFIES!
+            c = array.array('i', [2])
+            b.wait()
+            a += c
+
+        def inplace_concat2(b, a, c):  # MODIFIES!
+            b.wait()
+            a += c
+
+        def inplace_repeat2(b, a):  # MODIFIES!
+            b.wait()
+            a *= 2
+
+        def clear(b, a, *args):  # MODIFIES!
+            b.wait()
+            a.clear()
+
+        def clear2(b, a, c):  # MODIFIES c!
+            b.wait()
+            try: c.clear()
+            except BufferError: pass
+
+        def remove1(b, a):  # MODIFIES!
+            b.wait()
+            try: a.remove(1)
+            except ValueError: pass
+
+        def fromunicode(b, a):  # MODIFIES!
+            b.wait()
+            a.fromunicode('test')
+
+        def frombytes(b, a):  # MODIFIES!
+            b.wait()
+            a.frombytes(b'0000')
+
+        def frombytes2(b, a, c):  # MODIFIES!
+            b.wait()
+            a.frombytes(c)
+
+        def fromlist(b, a):  # MODIFIES!
+            n = random.randint(0, 100)
+            b.wait()
+            a.fromlist([2] * n)
+
+        def ass_subscr2(b, a, c):  # MODIFIES!
+            b.wait()
+            a[:] = c
+
+        def ass0(b, a):  # modifies inplace
+            b.wait()
+            try: a[0] = 0
+            except IndexError: pass
+
+        def byteswap(b, a):  # modifies inplace
+            b.wait()
+            a.byteswap()
+
+        def tounicode(b, a):
+            b.wait()
+            a.tounicode()
+
+        def tobytes(b, a):
+            b.wait()
+            a.tobytes()
+
+        def tolist(b, a):
+            b.wait()
+            a.tolist()
+
+        def tofile(b, a):
+            f = io.BytesIO()
+            b.wait()
+            a.tofile(f)
+
+        def reduce_ex2(b, a):
+            b.wait()
+            a.__reduce_ex__(2)
+
+        def reduce_ex3(b, a):
+            b.wait()
+            c = a.__reduce_ex__(3)
+            assert not c[1] or 0xdd not in c[1][3]
+
+        def copy(b, a):
+            b.wait()
+            c = a.__copy__()
+            assert not c or 0xdd not in c
+
+        def repr1(b, a):
+            b.wait()
+            repr(a)
+
+        def repeat2(b, a):
+            b.wait()
+            a * 2
+
+        def count1(b, a):
+            b.wait()
+            a.count(1)
+
+        def index1(b, a):
+            b.wait()
+            try: a.index(1)
+            except ValueError: pass
+
+        def contains1(b, a):
+            b.wait()
+            try: 1 in a
+            except ValueError: pass
+
+        def subscr0(b, a):
+            b.wait()
+            try: a[0]
+            except IndexError: pass
+
+        def concat(b, a):
+            b.wait()
+            a + a
+
+        def concat2(b, a, c):
+            b.wait()
+            a + c
+
+        def richcmplhs(b, a):
+            c = a[:]
+            b.wait()
+            a == c
+
+        def richcmprhs(b, a):
+            c = a[:]
+            b.wait()
+            c == a
+
+        def new(b, a):
+            tc = a.typecode
+            b.wait()
+            array.array(tc, a)
+
+        def repr_(b, a):
+            b.wait()
+            repr(a)
+
+        def irepeat(b, a):  # MODIFIES!
+            b.wait()
+            a *= 2
+
+        def newi(b, l):
+            b.wait()
+            array.array('i', l)
+
+        def fromlistl(b, a, l):  # MODIFIES!
+            b.wait()
+            a.fromlist(l)
+
+        def fromlistlclear(b, a, l):  # MODIFIES LIST!
+            b.wait()
+            l.clear()
+
+        def iter_next(b, a, it):  # MODIFIES ITERATOR!
+            b.wait()
+            list(it)
+
+        def iter_reduce(b, a, it):
+            b.wait()
+            c = it.__reduce__()
+            assert not c[1] or 0xdd not in c[1][0]
+
+        def check(funcs, a=None, *args):
+            if a is None:
+                a = array.array('i', [1])
+
+            barrier = threading.Barrier(len(funcs))
+            threads = []
+
+            for func in funcs:
+                thread = threading.Thread(target=func, args=(barrier, a, 
*args))
+
+                threads.append(thread)
+
+            with threading_helper.start_threads(threads):
+                pass
+
+        check([pop1] * 10)
+        check([pop1] + [subscr0] * 10)
+        check([append1] * 10)
+        check([insert1] * 10)
+        check([pop1] + [index1] * 10)
+        check([pop1] + [contains1] * 10)
+        check([insert1] + [repeat2] * 10)
+        check([pop1] + [repr1] * 10)
+        check([inplace_repeat2] * 10)
+        check([byteswap] * 10)
+        check([insert1] + [clear] * 10)
+        check([pop1] + [count1] * 10)
+        check([remove1] * 10)
+        check([clear] + [copy] * 10, array.array('B', b'0' * 0x400000))
+        check([pop1] + [reduce_ex2] * 10)
+        check([clear] + [reduce_ex3] * 10, array.array('B', b'0' * 0x400000))
+        check([pop1] + [tobytes] * 10)
+        check([pop1] + [tolist] * 10)
+        check([clear, tounicode] * 10, array.array('w', 'a'*10000))
+        check([clear, tofile] * 10, array.array('w', 'a'*10000))
+        check([clear] + [extend] * 10)
+        check([clear] + [inplace_concat] * 10)
+        check([clear] + [concat] * 10, array.array('w', 'a'*10000))
+        check([fromunicode] * 10, array.array('w', 'a'))
+        check([frombytes] * 10)
+        check([fromlist] * 10)
+        check([clear] + [richcmplhs] * 10, array.array('i', [1]*10000))
+        check([clear] + [richcmprhs] * 10, array.array('i', [1]*10000))
+        check([clear, ass0] * 10, array.array('i', [1]*10000))  # to test 
array_ass_item must disable Py_mp_ass_subscript
+        check([clear] + [new] * 10, array.array('w', 'a'*10000))
+        check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000))
+        check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000))
+        check([clear] + [irepeat] * 10, array.array('B', b'0' * 0x40000))
+        check([clear] + [iter_reduce] * 10, a := array.array('B', b'0' * 
0x400), iter(a))
+
+        # make sure we handle non-self objects correctly
+        check([clear] + [newi] * 10, [2] * random.randint(0, 100))
+        check([fromlistlclear] + [fromlistl] * 10, array.array('i', [1]), [2] 
* random.randint(0, 100))
+        check([clear2] + [concat2] * 10, array.array('w', 'a'*10000), 
array.array('w', 'a'*10000))
+        check([clear2] + [inplace_concat2] * 10, array.array('w', 'a'*10000), 
array.array('w', 'a'*10000))
+        check([clear2] + [extend2] * 10, array.array('w', 'a'*10000), 
array.array('w', 'a'*10000))
+        check([clear2] + [ass_subscr2] * 10, array.array('w', 'a'*10000), 
array.array('w', 'a'*10000))
+        check([clear2] + [frombytes2] * 10, array.array('w', 'a'*10000), 
array.array('B', b'a'*10000))
+
+        # iterator stuff
+        check([clear] + [iter_next] * 10, a := array.array('i', [1] * 10), 
iter(a))
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Library/2025-01-17-13-53-32.gh-issue-128942.DxzaIg.rst 
b/Misc/NEWS.d/next/Library/2025-01-17-13-53-32.gh-issue-128942.DxzaIg.rst
new file mode 100644
index 00000000000000..2b5eb581f1ffa1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-01-17-13-53-32.gh-issue-128942.DxzaIg.rst
@@ -0,0 +1 @@
+Make the :mod:`array` module safe under :term:`free threading`.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 5b86ec98393e48..0775b26e1d68ed 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -13,6 +13,7 @@
 #include "pycore_ceval.h"         // _PyEval_GetBuiltin()
 #include "pycore_modsupport.h"    // _PyArg_NoKeywords()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
+#include "pycore_pyatomic_ft_wrappers.h"
 
 #include <stddef.h>               // offsetof()
 #include <stdbool.h>
@@ -68,6 +69,19 @@ typedef struct {
     PyObject *str_iter;
 } array_state;
 
+static inline Py_ssize_t Pyarrayobject_GET_SIZE(PyObject *op) {
+    arrayobject *ao = (arrayobject *)op;
+#ifdef Py_GIL_DISABLED
+    return _Py_atomic_load_ssize_relaxed(&(_PyVarObject_CAST(ao)->ob_size));
+#else
+    return Py_SIZE(ao);
+#endif
+}
+#define Pyarrayobject_GET_SIZE(op) Pyarrayobject_GET_SIZE(_PyObject_CAST(op))
+
+/* Forward declaration. */
+static PyObject *array_array_frombytes(PyObject *self, PyObject *bytes);
+
 static array_state *
 get_array_state(PyObject *module)
 {
@@ -133,6 +147,7 @@ enum machine_format_code {
 static int
 array_resize(arrayobject *self, Py_ssize_t newsize)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
     char *items;
     size_t _new_size;
 
@@ -158,7 +173,7 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
         PyMem_Free(self->ob_item);
         self->ob_item = NULL;
         Py_SET_SIZE(self, 0);
-        self->allocated = 0;
+        FT_ATOMIC_STORE_SSIZE_RELAXED(self->allocated, 0);
         return 0;
     }
 
@@ -188,7 +203,7 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
     }
     self->ob_item = items;
     Py_SET_SIZE(self, newsize);
-    self->allocated = _new_size;
+    FT_ATOMIC_STORE_SSIZE_RELAXED(self->allocated, _new_size);
     return 0;
 }
 
@@ -672,6 +687,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const 
struct arraydescr *des
 static PyObject *
 getarrayitem(PyObject *op, Py_ssize_t i)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
 #ifndef NDEBUG
     array_state *state = find_array_state_by_type(Py_TYPE(op));
     assert(array_Check(op, state));
@@ -685,6 +701,7 @@ getarrayitem(PyObject *op, Py_ssize_t i)
 static int
 ins1(arrayobject *self, Py_ssize_t where, PyObject *v)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
     char *items;
     Py_ssize_t n = Py_SIZE(self);
     if (v == NULL) {
@@ -728,6 +745,11 @@ array_dealloc(PyObject *op)
     PyObject_GC_UnTrack(op);
 
     arrayobject *self = arrayobject_CAST(op);
+    if (self->ob_exports > 0) {
+        PyErr_SetString(PyExc_SystemError,
+                        "deallocated array object has exported buffers");
+        PyErr_Print();
+    }
     if (self->weakreflist != NULL) {
         PyObject_ClearWeakRefs(op);
     }
@@ -739,8 +761,10 @@ array_dealloc(PyObject *op)
 }
 
 static PyObject *
-array_richcompare(PyObject *v, PyObject *w, int op)
+array_richcompare_lock_held(PyObject *v, PyObject *w, int op)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(v);
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(w);
     array_state *state = find_array_state_by_type(Py_TYPE(v));
     arrayobject *va, *wa;
     PyObject *vi = NULL;
@@ -848,15 +872,27 @@ array_richcompare(PyObject *v, PyObject *w, int op)
     return res;
 }
 
+static PyObject *
+array_richcompare(PyObject *v, PyObject *w, int op)
+{
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION2(v, w);
+    ret = array_richcompare_lock_held(v, w, op);
+    Py_END_CRITICAL_SECTION2();
+    return ret;
+}
+
 static Py_ssize_t
 array_length(PyObject *op)
 {
-    return Py_SIZE(op);
+    arrayobject *self = arrayobject_CAST(op);
+    return Pyarrayobject_GET_SIZE(self);
 }
 
 static PyObject *
-array_item(PyObject *op, Py_ssize_t i)
+array_item_lock_held(PyObject *op, Py_ssize_t i)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     if (i < 0 || i >= Py_SIZE(op)) {
         PyErr_SetString(PyExc_IndexError, "array index out of range");
         return NULL;
@@ -864,9 +900,20 @@ array_item(PyObject *op, Py_ssize_t i)
     return getarrayitem(op, i);
 }
 
+static PyObject *
+array_item(PyObject *op, Py_ssize_t i)
+{
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_item_lock_held(op, i);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 static PyObject *
 array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(a);
     array_state *state = find_array_state_by_type(Py_TYPE(a));
     arrayobject *np;
 
@@ -891,6 +938,7 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t 
ihigh)
 }
 
 /*[clinic input]
+@critical_section
 array.array.clear
 
 Remove all items from the array.
@@ -898,7 +946,7 @@ Remove all items from the array.
 
 static PyObject *
 array_array_clear_impl(arrayobject *self)
-/*[clinic end generated code: output=5efe0417062210a9 input=5dffa30e94e717a4]*/
+/*[clinic end generated code: output=5efe0417062210a9 input=1c9dfcc80f5b6731]*/
 {
     if (array_resize(self, 0) == -1) {
         return NULL;
@@ -907,6 +955,7 @@ array_array_clear_impl(arrayobject *self)
 }
 
 /*[clinic input]
+@critical_section
 array.array.__copy__
 
 Return a copy of the array.
@@ -914,12 +963,13 @@ Return a copy of the array.
 
 static PyObject *
 array_array___copy___impl(arrayobject *self)
-/*[clinic end generated code: output=dec7c3f925d9619e input=ad1ee5b086965f09]*/
+/*[clinic end generated code: output=dec7c3f925d9619e input=7622f8f9489472d5]*/
 {
     return array_slice(self, 0, Py_SIZE(self));
 }
 
 /*[clinic input]
+@critical_section
 array.array.__deepcopy__
 
     unused: object
@@ -929,15 +979,17 @@ Return a copy of the array.
 [clinic start generated code]*/
 
 static PyObject *
-array_array___deepcopy__(arrayobject *self, PyObject *unused)
-/*[clinic end generated code: output=1ec748d8e14a9faa input=2405ecb4933748c4]*/
+array_array___deepcopy___impl(arrayobject *self, PyObject *unused)
+/*[clinic end generated code: output=703b4c412feaaf31 input=1a29f718f5b8a1dc]*/
 {
     return array_array___copy___impl(self);
 }
 
 static PyObject *
-array_concat(PyObject *op, PyObject *bb)
+array_concat_lock_held(PyObject *op, PyObject *bb)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb);
     arrayobject *a = arrayobject_CAST(op);
     array_state *state = find_array_state_by_type(Py_TYPE(a));
     Py_ssize_t size;
@@ -973,8 +1025,19 @@ array_concat(PyObject *op, PyObject *bb)
 }
 
 static PyObject *
-array_repeat(PyObject *op, Py_ssize_t n)
+array_concat(PyObject *op, PyObject *bb)
 {
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION2(op, bb);
+    ret = array_concat_lock_held(op, bb);
+    Py_END_CRITICAL_SECTION2();
+    return ret;
+}
+
+static PyObject *
+array_repeat_lock_held(PyObject *op, Py_ssize_t n)
+{
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     arrayobject *a = arrayobject_CAST(op);
     array_state *state = find_array_state_by_type(Py_TYPE(a));
 
@@ -998,9 +1061,20 @@ array_repeat(PyObject *op, Py_ssize_t n)
     return (PyObject *)np;
 }
 
+static PyObject *
+array_repeat(PyObject *op, Py_ssize_t n)
+{
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_repeat_lock_held(op, n);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 static int
 array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(a);
     char *item;
     Py_ssize_t d; /* Change in size */
     if (ilow < 0)
@@ -1034,8 +1108,9 @@ array_del_slice(arrayobject *a, Py_ssize_t ilow, 
Py_ssize_t ihigh)
 }
 
 static int
-array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v)
+setarrayitem(PyObject *op, Py_ssize_t i, PyObject *v)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     arrayobject *a = arrayobject_CAST(op);
     if (i < 0 || i >= Py_SIZE(a)) {
         PyErr_SetString(PyExc_IndexError,
@@ -1048,18 +1123,20 @@ array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v)
 }
 
 static int
-setarrayitem(PyObject *a, Py_ssize_t i, PyObject *v)
+array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v)
 {
-#ifndef NDEBUG
-    array_state *state = find_array_state_by_type(Py_TYPE(a));
-    assert(array_Check(a, state));
-#endif
-    return array_ass_item(a, i, v);
+    int ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = setarrayitem(op, i, v);
+    Py_END_CRITICAL_SECTION();
+    return ret;
 }
 
 static int
 array_iter_extend(arrayobject *self, PyObject *bb)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb);
     PyObject *it, *v;
 
     it = PyObject_GetIter(bb);
@@ -1081,8 +1158,10 @@ array_iter_extend(arrayobject *self, PyObject *bb)
 }
 
 static int
-array_do_extend(array_state *state, arrayobject *self, PyObject *bb)
+array_do_extend_lock_held(array_state *state, arrayobject *self, PyObject *bb)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb);
     Py_ssize_t size, oldsize, bbsize;
 
     if (!array_Check(bb, state))
@@ -1113,6 +1192,16 @@ array_do_extend(array_state *state, arrayobject *self, 
PyObject *bb)
 #undef b
 }
 
+static int
+array_do_extend(array_state *state, arrayobject *self, PyObject *bb)
+{
+    int ret;
+    Py_BEGIN_CRITICAL_SECTION2(self, bb);
+    ret = array_do_extend_lock_held(state, self, bb);
+    Py_END_CRITICAL_SECTION2();
+    return ret;
+}
+
 static PyObject *
 array_inplace_concat(PyObject *op, PyObject *bb)
 {
@@ -1131,8 +1220,9 @@ array_inplace_concat(PyObject *op, PyObject *bb)
 }
 
 static PyObject *
-array_inplace_repeat(PyObject *op, Py_ssize_t n)
+array_inplace_repeat_lock_held(PyObject *op, Py_ssize_t n)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     arrayobject *self = arrayobject_CAST(op);
     const Py_ssize_t array_size = Py_SIZE(self);
 
@@ -1155,16 +1245,19 @@ array_inplace_repeat(PyObject *op, Py_ssize_t n)
     return Py_NewRef(self);
 }
 
-
 static PyObject *
-ins(arrayobject *self, Py_ssize_t where, PyObject *v)
+array_inplace_repeat(PyObject *op, Py_ssize_t n)
 {
-    if (ins1(self, where, v) != 0)
-        return NULL;
-    Py_RETURN_NONE;
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_inplace_repeat_lock_held(op, n);
+    Py_END_CRITICAL_SECTION();
+    return ret;
 }
 
+
 /*[clinic input]
+@critical_section
 array.array.count
 
     v: object
@@ -1174,8 +1267,8 @@ Return number of occurrences of v in the array.
 [clinic start generated code]*/
 
 static PyObject *
-array_array_count(arrayobject *self, PyObject *v)
-/*[clinic end generated code: output=3dd3624bf7135a3a input=d9bce9d65e39d1f5]*/
+array_array_count_impl(arrayobject *self, PyObject *v)
+/*[clinic end generated code: output=93ead26a2affb739 input=c12c0042c1d0e27e]*/
 {
     Py_ssize_t count = 0;
     Py_ssize_t i;
@@ -1199,6 +1292,7 @@ array_array_count(arrayobject *self, PyObject *v)
 
 
 /*[clinic input]
+@critical_section
 array.array.index
 
     v: object
@@ -1214,7 +1308,7 @@ Raise ValueError if the value is not present.
 static PyObject *
 array_array_index_impl(arrayobject *self, PyObject *v, Py_ssize_t start,
                        Py_ssize_t stop)
-/*[clinic end generated code: output=c45e777880c99f52 input=089dff7baa7e5a7e]*/
+/*[clinic end generated code: output=c45e777880c99f52 input=fa32ac8ec22175d6]*/
 {
     if (start < 0) {
         start += Py_SIZE(self);
@@ -1247,22 +1341,34 @@ array_array_index_impl(arrayobject *self, PyObject *v, 
Py_ssize_t start,
 }
 
 static int
-array_contains(PyObject *self, PyObject *v)
+array_contains_lock_held(PyObject *op, PyObject *v)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     Py_ssize_t i;
     int cmp;
 
-    for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) {
-        PyObject *selfi = getarrayitem(self, i);
-        if (selfi == NULL)
+    for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(op); i++) {
+        PyObject *opi = getarrayitem(op, i);
+        if (opi == NULL)
             return -1;
-        cmp = PyObject_RichCompareBool(selfi, v, Py_EQ);
-        Py_DECREF(selfi);
+        cmp = PyObject_RichCompareBool(opi, v, Py_EQ);
+        Py_DECREF(opi);
     }
     return cmp;
 }
 
+static int
+array_contains(PyObject *op, PyObject *v)
+{
+    int ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_contains_lock_held(op, v);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 /*[clinic input]
+@critical_section
 array.array.remove
 
     v: object
@@ -1272,8 +1378,8 @@ Remove the first occurrence of v in the array.
 [clinic start generated code]*/
 
 static PyObject *
-array_array_remove(arrayobject *self, PyObject *v)
-/*[clinic end generated code: output=bef06be9fdf9dceb input=0b1e5aed25590027]*/
+array_array_remove_impl(arrayobject *self, PyObject *v)
+/*[clinic end generated code: output=f2a24e288ecb2a35 input=78bef3fd40e62f7a]*/
 {
     Py_ssize_t i;
 
@@ -1299,6 +1405,7 @@ array_array_remove(arrayobject *self, PyObject *v)
 }
 
 /*[clinic input]
+@critical_section
 array.array.pop
 
     i: Py_ssize_t = -1
@@ -1311,7 +1418,7 @@ i defaults to -1.
 
 static PyObject *
 array_array_pop_impl(arrayobject *self, Py_ssize_t i)
-/*[clinic end generated code: output=bc1f0c54fe5308e4 input=8e5feb4c1a11cd44]*/
+/*[clinic end generated code: output=bc1f0c54fe5308e4 input=c69a7f1f8c570e2f]*/
 {
     PyObject *v;
 
@@ -1358,6 +1465,7 @@ array_array_extend_impl(arrayobject *self, PyTypeObject 
*cls, PyObject *bb)
 }
 
 /*[clinic input]
+@critical_section
 array.array.insert
 
     i: Py_ssize_t
@@ -1369,12 +1477,15 @@ Insert a new item v into the array before position i.
 
 static PyObject *
 array_array_insert_impl(arrayobject *self, Py_ssize_t i, PyObject *v)
-/*[clinic end generated code: output=5a3648e278348564 input=5577d1b4383e9313]*/
+/*[clinic end generated code: output=5a3648e278348564 input=3c922bbd81462978]*/
 {
-    return ins(self, i, v);
+    if (ins1(self, i, v) != 0)
+        return NULL;
+    Py_RETURN_NONE;
 }
 
 /*[clinic input]
+@critical_section
 array.array.buffer_info
 
 Return a tuple (address, length) giving the current memory address and the 
length in items of the buffer used to hold array's contents.
@@ -1385,7 +1496,7 @@ the buffer length in bytes.
 
 static PyObject *
 array_array_buffer_info_impl(arrayobject *self)
-/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=a58bae5c6e1ac6a6]*/
+/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=9d0dc1ff0e6542e8]*/
 {
     PyObject *retval = NULL, *v;
 
@@ -1411,6 +1522,7 @@ array_array_buffer_info_impl(arrayobject *self)
 }
 
 /*[clinic input]
+@critical_section
 array.array.append
 
     v: object
@@ -1420,13 +1532,16 @@ Append new value v to the end of the array.
 [clinic start generated code]*/
 
 static PyObject *
-array_array_append(arrayobject *self, PyObject *v)
-/*[clinic end generated code: output=745a0669bf8db0e2 input=0b98d9d78e78f0fa]*/
+array_array_append_impl(arrayobject *self, PyObject *v)
+/*[clinic end generated code: output=2f1e8cbad70c2a8b input=9cdd897c66a40c3f]*/
 {
-    return ins(self, Py_SIZE(self), v);
+    if (ins1(self, Py_SIZE(self), v) != 0)
+        return NULL;
+    Py_RETURN_NONE;
 }
 
 /*[clinic input]
+@critical_section
 array.array.byteswap
 
 Byteswap all items of the array.
@@ -1437,7 +1552,7 @@ raised.
 
 static PyObject *
 array_array_byteswap_impl(arrayobject *self)
-/*[clinic end generated code: output=5f8236cbdf0d90b5 input=6a85591b950a0186]*/
+/*[clinic end generated code: output=5f8236cbdf0d90b5 input=e691b6eff94d8b2e]*/
 {
     char *p;
     Py_ssize_t i;
@@ -1487,6 +1602,7 @@ array_array_byteswap_impl(arrayobject *self)
 }
 
 /*[clinic input]
+@critical_section
 array.array.reverse
 
 Reverse the order of the items in the array.
@@ -1494,7 +1610,7 @@ Reverse the order of the items in the array.
 
 static PyObject *
 array_array_reverse_impl(arrayobject *self)
-/*[clinic end generated code: output=c04868b36f6f4089 input=cd904f01b27d966a]*/
+/*[clinic end generated code: output=c04868b36f6f4089 input=e3947e98aed068ed]*/
 {
     Py_ssize_t itemsize = self->ob_descr->itemsize;
     char *p, *q;
@@ -1584,6 +1700,7 @@ array_array_fromfile_impl(arrayobject *self, PyTypeObject 
*cls, PyObject *f,
 }
 
 /*[clinic input]
+@critical_section
 array.array.tofile
 
     cls: defining_class
@@ -1595,7 +1712,7 @@ Write all items (as machine values) to the file object f.
 
 static PyObject *
 array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f)
-/*[clinic end generated code: output=4560c628d9c18bc2 input=5a24da7a7b407b52]*/
+/*[clinic end generated code: output=4560c628d9c18bc2 input=a26bc66df57864dd]*/
 {
     Py_ssize_t nbytes = Py_SIZE(self) * self->ob_descr->itemsize;
     /* Write 64K blocks at a time */
@@ -1628,11 +1745,12 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject 
*cls, PyObject *f)
         Py_DECREF(res); /* drop write result */
     }
 
-  done:
+done:
     Py_RETURN_NONE;
 }
 
 /*[clinic input]
+@critical_section self list
 array.array.fromlist
 
     list: object
@@ -1642,8 +1760,8 @@ Append items to array from list.
 [clinic start generated code]*/
 
 static PyObject *
-array_array_fromlist(arrayobject *self, PyObject *list)
-/*[clinic end generated code: output=26411c2d228a3e3f input=be2605a96c49680f]*/
+array_array_fromlist_impl(arrayobject *self, PyObject *list)
+/*[clinic end generated code: output=6c23733a68dd68df input=c7c056aaf85d997a]*/
 {
     Py_ssize_t n;
 
@@ -1676,6 +1794,7 @@ array_array_fromlist(arrayobject *self, PyObject *list)
 }
 
 /*[clinic input]
+@critical_section
 array.array.tolist
 
 Convert array to an ordinary list with the same items.
@@ -1683,7 +1802,7 @@ Convert array to an ordinary list with the same items.
 
 static PyObject *
 array_array_tolist_impl(arrayobject *self)
-/*[clinic end generated code: output=00b60cc9eab8ef89 input=a8d7784a94f86b53]*/
+/*[clinic end generated code: output=00b60cc9eab8ef89 input=4543fdbac475c52c]*/
 {
     PyObject *list = PyList_New(Py_SIZE(self));
     Py_ssize_t i;
@@ -1703,19 +1822,29 @@ array_array_tolist_impl(arrayobject *self)
     return NULL;
 }
 
+
+/*[clinic input]
+@critical_section
+array.array.frombytes
+
+    buffer: Py_buffer
+    /
+
+Appends items from the string, interpreting it as an array of machine values, 
as if it had been read from a file using the fromfile() method.
+[clinic start generated code]*/
+
 static PyObject *
-frombytes(arrayobject *self, Py_buffer *buffer)
+array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer)
+/*[clinic end generated code: output=d9842c8f7510a516 input=2245f9ea58579960]*/
 {
     int itemsize = self->ob_descr->itemsize;
     Py_ssize_t n;
     if (buffer->itemsize != 1) {
-        PyBuffer_Release(buffer);
         PyErr_SetString(PyExc_TypeError, "a bytes-like object is required");
         return NULL;
     }
     n = buffer->len;
     if (n % itemsize != 0) {
-        PyBuffer_Release(buffer);
         PyErr_SetString(PyExc_ValueError,
                    "bytes length not a multiple of item size");
         return NULL;
@@ -1725,37 +1854,19 @@ frombytes(arrayobject *self, Py_buffer *buffer)
         Py_ssize_t old_size = Py_SIZE(self);
         if ((n > PY_SSIZE_T_MAX - old_size) ||
             ((old_size + n) > PY_SSIZE_T_MAX / itemsize)) {
-                PyBuffer_Release(buffer);
                 return PyErr_NoMemory();
         }
         if (array_resize(self, old_size + n) == -1) {
-            PyBuffer_Release(buffer);
             return NULL;
         }
         memcpy(self->ob_item + old_size * itemsize,
             buffer->buf, n * itemsize);
     }
-    PyBuffer_Release(buffer);
     Py_RETURN_NONE;
 }
 
 /*[clinic input]
-array.array.frombytes
-
-    buffer: Py_buffer
-    /
-
-Appends items from the string, interpreting it as an array of machine values, 
as if it had been read from a file using the fromfile() method.
-[clinic start generated code]*/
-
-static PyObject *
-array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer)
-/*[clinic end generated code: output=d9842c8f7510a516 input=378db226dfac949e]*/
-{
-    return frombytes(self, buffer);
-}
-
-/*[clinic input]
+@critical_section
 array.array.tobytes
 
 Convert the array to an array of machine values and return the bytes 
representation.
@@ -1763,7 +1874,7 @@ Convert the array to an array of machine values and 
return the bytes representat
 
 static PyObject *
 array_array_tobytes_impl(arrayobject *self)
-/*[clinic end generated code: output=87318e4edcdc2bb6 input=90ee495f96de34f5]*/
+/*[clinic end generated code: output=87318e4edcdc2bb6 input=c4d44d5499d2320f]*/
 {
     if (Py_SIZE(self) <= PY_SSIZE_T_MAX / self->ob_descr->itemsize) {
         return PyBytes_FromStringAndSize(self->ob_item,
@@ -1774,6 +1885,7 @@ array_array_tobytes_impl(arrayobject *self)
 }
 
 /*[clinic input]
+@critical_section
 array.array.fromunicode
 
     ustr: unicode
@@ -1788,7 +1900,7 @@ some other type.
 
 static PyObject *
 array_array_fromunicode_impl(arrayobject *self, PyObject *ustr)
-/*[clinic end generated code: output=24359f5e001a7f2b input=025db1fdade7a4ce]*/
+/*[clinic end generated code: output=24359f5e001a7f2b input=01e2a776cee82011]*/
 {
     int typecode = self->ob_descr->typecode;
     if (typecode != 'u' && typecode != 'w') {
@@ -1836,6 +1948,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject 
*ustr)
 }
 
 /*[clinic input]
+@critical_section
 array.array.tounicode
 
 Extends this array with data from the unicode string ustr.
@@ -1847,7 +1960,7 @@ unicode string from an array of some other type.
 
 static PyObject *
 array_array_tounicode_impl(arrayobject *self)
-/*[clinic end generated code: output=08e442378336e1ef input=127242eebe70b66d]*/
+/*[clinic end generated code: output=08e442378336e1ef input=6c69dfe81a279b91]*/
 {
     int typecode = self->ob_descr->typecode;
     if (typecode != 'u' && typecode != 'w') {
@@ -1876,7 +1989,8 @@ array_array___sizeof___impl(arrayobject *self)
 /*[clinic end generated code: output=d8e1c61ebbe3eaed input=805586565bf2b3c6]*/
 {
     size_t res = _PyObject_SIZE(Py_TYPE(self));
-    res += (size_t)self->allocated * (size_t)self->ob_descr->itemsize;
+    res += (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(self->allocated)
+        * (size_t)self->ob_descr->itemsize;
     return PyLong_FromSize_t(res);
 }
 
@@ -2271,6 +2385,7 @@ array__array_reconstructor_impl(PyObject *module, 
PyTypeObject *arraytype,
 }
 
 /*[clinic input]
+@critical_section
 array.array.__reduce_ex__
 
     cls: defining_class
@@ -2283,7 +2398,7 @@ Return state information for pickling.
 static PyObject *
 array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls,
                                PyObject *value)
-/*[clinic end generated code: output=4958ee5d79452ad5 input=19968cf0f91d3eea]*/
+/*[clinic end generated code: output=4958ee5d79452ad5 input=18c90a4cad7ac527]*/
 {
     PyObject *dict;
     PyObject *result;
@@ -2411,8 +2526,9 @@ static PyMethodDef array_methods[] = {
 };
 
 static PyObject *
-array_repr(PyObject *op)
+array_repr_lock_held(PyObject *op)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     char typecode;
     PyObject *s, *v = NULL;
     Py_ssize_t len;
@@ -2438,9 +2554,20 @@ array_repr(PyObject *op)
     return s;
 }
 
+static PyObject *
+array_repr(PyObject *op)
+{
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_repr_lock_held(op);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 static PyObject*
-array_subscr(PyObject *op, PyObject *item)
+array_subscr_lock_held(PyObject *op, PyObject *item)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
     arrayobject *self = arrayobject_CAST(op);
     array_state *state = find_array_state_by_type(Py_TYPE(self));
 
@@ -2502,12 +2629,28 @@ array_subscr(PyObject *op, PyObject *item)
     }
 }
 
+static PyObject *
+array_subscr(PyObject *op, PyObject *item)
+{
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_subscr_lock_held(op, item);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 static int
-array_ass_subscr(PyObject *op, PyObject *item, PyObject *value)
+array_ass_subscr_lock_held(PyObject *op, PyObject* item, PyObject* value)
 {
-    Py_ssize_t start, stop, step, slicelength, needed;
+    array_state* state = find_array_state_by_type(Py_TYPE(op));
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+#ifdef Py_DEBUG
+    if (value != NULL && array_Check(value, state)) {
+        _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(value);
+    }
+#endif
     arrayobject *self = arrayobject_CAST(op);
-    array_state* state = find_array_state_by_type(Py_TYPE(self));
+    Py_ssize_t start, stop, step, slicelength, needed;
     arrayobject* other;
     int itemsize;
 
@@ -2558,7 +2701,7 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject 
*value)
             value = array_slice(other, 0, needed);
             if (value == NULL)
                 return -1;
-            ret = array_ass_subscr(op, item, value);
+            ret = array_ass_subscr_lock_held(op, item, value);
             Py_DECREF(value);
             return ret;
         }
@@ -2661,19 +2804,38 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject 
*value)
     }
 }
 
+static int
+array_ass_subscr(PyObject *op, PyObject* item, PyObject* value)
+{
+    int ret;
+    array_state* state = find_array_state_by_type(Py_TYPE(op));
+    if (value != NULL && array_Check(value, state)) {
+        Py_BEGIN_CRITICAL_SECTION2(op, value);
+        ret = array_ass_subscr_lock_held(op, item, value);
+        Py_END_CRITICAL_SECTION2();
+    }
+    else {
+        Py_BEGIN_CRITICAL_SECTION(op);
+        ret = array_ass_subscr_lock_held(op, item, value);
+        Py_END_CRITICAL_SECTION();
+    }
+    return ret;
+}
+
 static const void *emptybuf = "";
 
 
 static int
-array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags)
+array_buffer_getbuf_lock_held(PyObject *op, Py_buffer *view, int flags)
 {
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
+    arrayobject *self = arrayobject_CAST(op);
     if (view == NULL) {
         PyErr_SetString(PyExc_BufferError,
             "array_buffer_getbuf: view==NULL argument is obsolete");
         return -1;
     }
 
-    arrayobject *self = arrayobject_CAST(op);
     view->buf = (void *)self->ob_item;
     view->obj = Py_NewRef(self);
     if (view->buf == NULL)
@@ -2705,61 +2867,39 @@ array_buffer_getbuf(PyObject *op, Py_buffer *view, int 
flags)
     return 0;
 }
 
+static int
+array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags)
+{
+    int ret;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    ret = array_buffer_getbuf_lock_held(op, view, flags);
+    Py_END_CRITICAL_SECTION();
+    return ret;
+}
+
 static void
 array_buffer_relbuf(PyObject *op, Py_buffer *Py_UNUSED(view))
 {
+    Py_BEGIN_CRITICAL_SECTION(op);
     arrayobject *self = arrayobject_CAST(op);
     self->ob_exports--;
+    assert(self->ob_exports >= 0);
+    Py_END_CRITICAL_SECTION();
 }
 
 static PyObject *
-array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+array_new_internal_lock_held(PyTypeObject *type, PyObject *initial, int c)
 {
+#ifdef Py_DEBUG
+    if (initial != NULL) {
+        _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(initial);
+    }
+#endif
     array_state *state = find_array_state_by_type(type);
-    int c;
-    PyObject *initial = NULL, *it = NULL;
+    PyObject *it = NULL;
     const struct arraydescr *descr;
-
-    if ((type == state->ArrayType ||
-         type->tp_init == state->ArrayType->tp_init) &&
-        !_PyArg_NoKeywords("array.array", kwds))
-        return NULL;
-
-    if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial))
-        return NULL;
-
-    if (PySys_Audit("array.__new__", "CO",
-                    c, initial ? initial : Py_None) < 0) {
-        return NULL;
-    }
-
-    if (c == 'u') {
-        if (PyErr_WarnEx(PyExc_DeprecationWarning,
-                         "The 'u' type code is deprecated and "
-                         "will be removed in Python 3.16",
-                         1)) {
-            return NULL;
-        }
-    }
-
     bool is_unicode = c == 'u' || c == 'w';
 
-    if (initial && !is_unicode) {
-        if (PyUnicode_Check(initial)) {
-            PyErr_Format(PyExc_TypeError, "cannot use a str to initialize "
-                         "an array with typecode '%c'", c);
-            return NULL;
-        }
-        else if (array_Check(initial, state)) {
-            int ic = ((arrayobject*)initial)->ob_descr->typecode;
-            if (ic == 'u' || ic == 'w') {
-                PyErr_Format(PyExc_TypeError, "cannot use a unicode array to "
-                            "initialize an array with typecode '%c'", c);
-                return NULL;
-            }
-        }
-    }
-
     if (!(initial == NULL || PyList_Check(initial)
           || PyByteArray_Check(initial)
           || PyBytes_Check(initial)
@@ -2877,6 +3017,69 @@ array_new(PyTypeObject *type, PyObject *args, PyObject 
*kwds)
     return NULL;
 }
 
+static PyObject *
+array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    array_state *state = find_array_state_by_type(type);
+    int c;
+    PyObject *initial = NULL;
+
+    if ((type == state->ArrayType ||
+         type->tp_init == state->ArrayType->tp_init) &&
+        !_PyArg_NoKeywords("array.array", kwds)) {
+        return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial)) {
+        return NULL;
+    }
+
+    if (PySys_Audit("array.__new__", "CO",
+                    c, initial ? initial : Py_None) < 0) {
+        return NULL;
+    }
+
+    if (c == 'u') {
+        if (PyErr_WarnEx(PyExc_DeprecationWarning,
+                         "The 'u' type code is deprecated and "
+                         "will be removed in Python 3.16",
+                         1)) {
+            return NULL;
+        }
+    }
+
+    bool is_unicode = c == 'u' || c == 'w';
+
+    if (initial && !is_unicode) {
+        if (PyUnicode_Check(initial)) {
+            PyErr_Format(PyExc_TypeError, "cannot use a str to initialize "
+                         "an array with typecode '%c'", c);
+            return NULL;
+        }
+        else if (array_Check(initial, state)) {
+            int ic = ((arrayobject*)initial)->ob_descr->typecode;
+            if (ic == 'u' || ic == 'w') {
+                PyErr_Format(PyExc_TypeError, "cannot use a unicode array to "
+                            "initialize an array with typecode '%c'", c);
+                return NULL;
+            }
+        }
+    }
+
+    PyObject *ret;
+
+    if (initial == NULL) {
+        ret = array_new_internal_lock_held(type, initial, c);
+    }
+    else {
+        Py_BEGIN_CRITICAL_SECTION(initial);
+        ret = array_new_internal_lock_held(type, initial, c);
+        Py_END_CRITICAL_SECTION();
+    }
+
+    return ret;
+}
+
 
 PyDoc_STRVAR(module_doc,
 "This module defines an object type which can efficiently represent\n\
@@ -3019,7 +3222,7 @@ array_iter(PyObject *op)
         return NULL;
 
     it->ao = (arrayobject*)Py_NewRef(ao);
-    it->index = 0;
+    it->index = 0;  // -1 indicates exhausted
     it->getitem = ao->ob_descr->getitem;
     PyObject_GC_Track(it);
     return (PyObject *)it;
@@ -3030,23 +3233,37 @@ arrayiter_next(PyObject *op)
 {
     arrayiterobject *it = arrayiterobject_CAST(op);
     assert(it != NULL);
+    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->index);
+    if (index < 0) {
+        return NULL;
+    }
+    PyObject *ret;
+    arrayobject *ao = it->ao;
 #ifndef NDEBUG
     array_state *state = find_array_state_by_type(Py_TYPE(it));
     assert(PyObject_TypeCheck(it, state->ArrayIterType));
+    assert(array_Check(ao, state));
 #endif
-    arrayobject *ao = it->ao;
-    if (ao == NULL) {
-        return NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(ao);
+    if (index < Py_SIZE(ao)) {
+        ret = (*it->getitem)(ao, index);
     }
-#ifndef NDEBUG
-    assert(array_Check(ao, state));
+    else {
+        ret = NULL;
+    }
+    Py_END_CRITICAL_SECTION();
+
+    if (ret != NULL) {
+        FT_ATOMIC_STORE_SSIZE_RELAXED(it->index, index + 1);
+    }
+    else {
+        FT_ATOMIC_STORE_SSIZE_RELAXED(it->index, -1);
+#ifndef Py_GIL_DISABLED
+        Py_CLEAR(it->ao);
 #endif
-    if (it->index < Py_SIZE(ao)) {
-        return (*it->getitem)(ao, it->index++);
     }
-    it->ao = NULL;
-    Py_DECREF(ao);
-    return NULL;
+    return ret;
 }
 
 static void
@@ -3082,14 +3299,14 @@ static PyObject *
 array_arrayiterator___reduce___impl(arrayiterobject *self, PyTypeObject *cls)
 /*[clinic end generated code: output=4b032417a2c8f5e6 input=ac64e65a87ad452e]*/
 {
-
     array_state *state = get_array_state_by_class(cls);
     assert(state != NULL);
     PyObject *func = _PyEval_GetBuiltin(state->str_iter);
-    if (self->ao == NULL) {
-        return Py_BuildValue("N(())", func);
+    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->index);
+    if (index >= 0) {
+        return Py_BuildValue("N(O)n", func, self->ao, index);
     }
-    return Py_BuildValue("N(O)n", func, self->ao, self->index);
+    return Py_BuildValue("N(())", func);
 }
 
 /*[clinic input]
@@ -3106,17 +3323,20 @@ array_arrayiterator___setstate__(arrayiterobject *self, 
PyObject *state)
 /*[clinic end generated code: output=397da9904e443cbe input=f47d5ceda19e787b]*/
 {
     Py_ssize_t index = PyLong_AsSsize_t(state);
-    if (index == -1 && PyErr_Occurred())
+    if (index == -1 && PyErr_Occurred()) {
         return NULL;
-    arrayobject *ao = self->ao;
-    if (ao != NULL) {
-        if (index < 0) {
-            index = 0;
+    }
+    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->index) >= 0) {
+        if (index < -1) {
+            index = -1;
         }
-        else if (index > Py_SIZE(ao)) {
-            index = Py_SIZE(ao); /* iterator exhausted */
+        else {
+            Py_ssize_t size = Pyarrayobject_GET_SIZE(self->ao);
+            if (index > size) {
+                index = size; /* iterator at end */
+            }
         }
-        self->index = index;
+        FT_ATOMIC_STORE_SSIZE_RELAXED(self->index, index);
     }
     Py_RETURN_NONE;
 }
diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h
index c5b62b16699d06..3816bb7709658e 100644
--- a/Modules/clinic/arraymodule.c.h
+++ b/Modules/clinic/arraymodule.c.h
@@ -6,6 +6,7 @@ preserve
 #  include "pycore_runtime.h"     // _Py_SINGLETON()
 #endif
 #include "pycore_abstract.h"      // _PyNumber_Index()
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
 #include "pycore_modsupport.h"    // _PyArg_CheckPositional()
 
 PyDoc_STRVAR(array_array_clear__doc__,
@@ -23,7 +24,13 @@ array_array_clear_impl(arrayobject *self);
 static PyObject *
 array_array_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_clear_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_clear_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array___copy____doc__,
@@ -41,7 +48,13 @@ array_array___copy___impl(arrayobject *self);
 static PyObject *
 array_array___copy__(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array___copy___impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array___copy___impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array___deepcopy____doc__,
@@ -53,6 +66,21 @@ PyDoc_STRVAR(array_array___deepcopy____doc__,
 #define ARRAY_ARRAY___DEEPCOPY___METHODDEF    \
     {"__deepcopy__", (PyCFunction)array_array___deepcopy__, METH_O, 
array_array___deepcopy____doc__},
 
+static PyObject *
+array_array___deepcopy___impl(arrayobject *self, PyObject *unused);
+
+static PyObject *
+array_array___deepcopy__(arrayobject *self, PyObject *unused)
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array___deepcopy___impl((arrayobject *)self, unused);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(array_array_count__doc__,
 "count($self, v, /)\n"
 "--\n"
@@ -62,6 +90,21 @@ PyDoc_STRVAR(array_array_count__doc__,
 #define ARRAY_ARRAY_COUNT_METHODDEF    \
     {"count", (PyCFunction)array_array_count, METH_O, 
array_array_count__doc__},
 
+static PyObject *
+array_array_count_impl(arrayobject *self, PyObject *v);
+
+static PyObject *
+array_array_count(arrayobject *self, PyObject *v)
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_count_impl((arrayobject *)self, v);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(array_array_index__doc__,
 "index($self, v, start=0, stop=sys.maxsize, /)\n"
 "--\n"
@@ -102,7 +145,9 @@ array_array_index(PyObject *self, PyObject *const *args, 
Py_ssize_t nargs)
         goto exit;
     }
 skip_optional:
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_index_impl((arrayobject *)self, v, start, stop);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -117,6 +162,21 @@ PyDoc_STRVAR(array_array_remove__doc__,
 #define ARRAY_ARRAY_REMOVE_METHODDEF    \
     {"remove", (PyCFunction)array_array_remove, METH_O, 
array_array_remove__doc__},
 
+static PyObject *
+array_array_remove_impl(arrayobject *self, PyObject *v);
+
+static PyObject *
+array_array_remove(arrayobject *self, PyObject *v)
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_remove_impl((arrayobject *)self, v);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(array_array_pop__doc__,
 "pop($self, i=-1, /)\n"
 "--\n"
@@ -156,7 +216,9 @@ array_array_pop(PyObject *self, PyObject *const *args, 
Py_ssize_t nargs)
         i = ival;
     }
 skip_optional:
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_pop_impl((arrayobject *)self, i);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -241,7 +303,9 @@ array_array_insert(PyObject *self, PyObject *const *args, 
Py_ssize_t nargs)
         i = ival;
     }
     v = args[1];
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_insert_impl((arrayobject *)self, i, v);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -265,7 +329,13 @@ array_array_buffer_info_impl(arrayobject *self);
 static PyObject *
 array_array_buffer_info(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_buffer_info_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_buffer_info_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array_append__doc__,
@@ -277,6 +347,21 @@ PyDoc_STRVAR(array_array_append__doc__,
 #define ARRAY_ARRAY_APPEND_METHODDEF    \
     {"append", (PyCFunction)array_array_append, METH_O, 
array_array_append__doc__},
 
+static PyObject *
+array_array_append_impl(arrayobject *self, PyObject *v);
+
+static PyObject *
+array_array_append(arrayobject *self, PyObject *v)
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_append_impl((arrayobject *)self, v);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(array_array_byteswap__doc__,
 "byteswap($self, /)\n"
 "--\n"
@@ -295,7 +380,13 @@ array_array_byteswap_impl(arrayobject *self);
 static PyObject *
 array_array_byteswap(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_byteswap_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_byteswap_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array_reverse__doc__,
@@ -313,7 +404,13 @@ array_array_reverse_impl(arrayobject *self);
 static PyObject *
 array_array_reverse(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_reverse_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_reverse_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array_fromfile__doc__,
@@ -412,7 +509,9 @@ array_array_tofile(PyObject *self, PyTypeObject *cls, 
PyObject *const *args, Py_
         goto exit;
     }
     f = args[0];
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_tofile_impl((arrayobject *)self, cls, f);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -427,6 +526,21 @@ PyDoc_STRVAR(array_array_fromlist__doc__,
 #define ARRAY_ARRAY_FROMLIST_METHODDEF    \
     {"fromlist", (PyCFunction)array_array_fromlist, METH_O, 
array_array_fromlist__doc__},
 
+static PyObject *
+array_array_fromlist_impl(arrayobject *self, PyObject *list);
+
+static PyObject *
+array_array_fromlist(arrayobject *self, PyObject *list)
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION2(self, list);
+    return_value = array_array_fromlist_impl((arrayobject *)self, list);
+    Py_END_CRITICAL_SECTION2();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(array_array_tolist__doc__,
 "tolist($self, /)\n"
 "--\n"
@@ -442,7 +556,13 @@ array_array_tolist_impl(arrayobject *self);
 static PyObject *
 array_array_tolist(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_tolist_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_tolist_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array_frombytes__doc__,
@@ -466,7 +586,9 @@ array_array_frombytes(PyObject *self, PyObject *arg)
     if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) {
         goto exit;
     }
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_frombytes_impl((arrayobject *)self, &buffer);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     /* Cleanup for buffer */
@@ -492,7 +614,13 @@ array_array_tobytes_impl(arrayobject *self);
 static PyObject *
 array_array_tobytes(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_tobytes_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_tobytes_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array_fromunicode__doc__,
@@ -522,7 +650,9 @@ array_array_fromunicode(PyObject *self, PyObject *arg)
         goto exit;
     }
     ustr = arg;
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array_fromunicode_impl((arrayobject *)self, ustr);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -547,7 +677,13 @@ array_array_tounicode_impl(arrayobject *self);
 static PyObject *
 array_array_tounicode(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return array_array_tounicode_impl((arrayobject *)self);
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = array_array_tounicode_impl((arrayobject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
 }
 
 PyDoc_STRVAR(array_array___sizeof____doc__,
@@ -659,7 +795,9 @@ array_array___reduce_ex__(PyObject *self, PyTypeObject 
*cls, PyObject *const *ar
         goto exit;
     }
     value = args[0];
+    Py_BEGIN_CRITICAL_SECTION(self);
     return_value = array_array___reduce_ex___impl((arrayobject *)self, cls, 
value);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
@@ -695,4 +833,4 @@ PyDoc_STRVAR(array_arrayiterator___setstate____doc__,
 
 #define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF    \
     {"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, 
array_arrayiterator___setstate____doc__},
-/*[clinic end generated code: output=8120dc5c4fa414b9 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=c9219e074c62e0c8 input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to