--- a PPN by Garber Painting Akron. With Image Size Reduction included!URL: http://github.com/python/cpython/pull/148800.patch
er/cpython/ignored.tsv
@@ -542,6 +542,7 @@ Modules/_testcapimodule.c - meth_class_methods -
Modules/_testcapimodule.c - meth_instance_methods -
Modules/_testcapimodule.c - meth_static_methods -
Modules/_testcapimodule.c - ml -
+Modules/_testcapimodule.c - SpinningBarrier_Type -
Modules/_testcapimodule.c - str1 -
Modules/_testcapimodule.c - str2 -
Modules/_testcapimodule.c - test_c_thread -
From 7a7114bbefabbf032c4c434d092193250cff0b86 Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Mon, 20 Apr 2026 15:25:59 +0000
Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?=
=?UTF-8?q?rb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst | 1 +
1 file changed, 1 insertion(+)
create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
new file mode 100644
index 00000000000000..03374c174d3538
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
@@ -0,0 +1 @@
+Fix a sequential consistency bug in `structmember.c` and add `_testcapi.SpinningBarrier` to support the new test.
From 47b58c9035c96e9d477f3bc6003fa9718878edff Mon Sep 17 00:00:00 2001
From: Daniele Parmeggiani
Date: Mon, 20 Apr 2026 16:28:55 +0100
Subject: [PATCH 3/6] fix backticks
---
.../2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
index 03374c174d3538..339697d6f3132e 100644
--- a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
@@ -1 +1 @@
-Fix a sequential consistency bug in `structmember.c` and add `_testcapi.SpinningBarrier` to support the new test.
+Fix a sequential consistency bug in ``structmember.c`` and add ``_testcapi.SpinningBarrier`` to support the new test.
From 015795a841734df01c8fcec1cd47794a90415d4d Mon Sep 17 00:00:00 2001
From: Daniele Parmeggiani
Date: Tue, 21 Apr 2026 10:33:16 +0100
Subject: [PATCH 4/6] address some review comments
---
Python/structmember.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/Python/structmember.c b/Python/structmember.c
index 8cd2c928605bfa..adea8216b8796b 100644
--- a/Python/structmember.c
+++ b/Python/structmember.c
@@ -325,20 +325,16 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
oldv = *(PyObject **)addr;
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, Py_XNewRef(v));
Py_END_CRITICAL_SECTION();
- Py_XDECREF(oldv);
if (v == NULL && oldv == NULL && l->type == Py_T_OBJECT_EX) {
- // Pseudo-non-existing attribute is deleted: raise AttributeError.
- // The attribute doesn't exist to Python, but CPython knows that it
- // could have existed because it was declared in __slots__.
- // _Py_T_OBJECT does not raise an exception here, and
- // PyMember_GetOne will return Py_None instead of NULL.
+ // Raise an exception when attempting to delete an already deleted
+ // attribute.
+ // Differently from Py_T_OBJECT_EX, _Py_T_OBJECT does not raise an
+ // exception here (PyMember_GetOne will return Py_None instead of
+ // NULL).
PyErr_SetString(PyExc_AttributeError, l->name);
return -1;
}
- // Other cases are already covered by the above:
- // oldv == NULL && v != NULL: pseudo-non-existing attribute is set, ok
- // oldv != NULL && v == NULL: existing attribute is deleted, ok
- // oldv != NULL && v != NULL: existing attribute is set, ok
+ Py_XDECREF(oldv);
break;
case Py_T_CHAR: {
const char *string;
From 50c19f66a5a692d0047aa330408571dd0cfc95c1 Mon Sep 17 00:00:00 2001
From: Daniele Parmeggiani
Date: Tue, 21 Apr 2026 11:03:06 +0100
Subject: [PATCH 5/6] decrease number of iterations
---
Lib/test/test_free_threading/test_slots.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/Lib/test/test_free_threading/test_slots.py b/Lib/test/test_free_threading/test_slots.py
index 351819ca4ac19a..8357a2a75043b1 100644
--- a/Lib/test/test_free_threading/test_slots.py
+++ b/Lib/test/test_free_threading/test_slots.py
@@ -56,7 +56,6 @@ class Spam:
]
spam = Spam()
- iters = 1_000
non_seq_cst_behaviour_observed = False
def deleter():
@@ -80,7 +79,7 @@ def deleter():
# falsifying the assumption that `del spam.eggs` was
# atomic. The test fails if this point is reached.
- for _ in range(iters):
+ for _ in range(10):
spam.eggs = 0
spam.foo = 0
barrier = _testcapi.SpinningBarrier(2)
From e036ecc9190216d847e29159f163e3a33f209990 Mon Sep 17 00:00:00 2001
From: Daniele Parmeggiani
Date: Mon, 27 Apr 2026 13:31:40 +0100
Subject: [PATCH 6/6] change test and remove spinningbarrier
---
Lib/test/test_free_threading/test_slots.py | 57 +++------
...-04-20-15-25-55.gh-issue-146270.qZYfyc.rst | 2 +-
Modules/_testcapimodule.c | 108 ------------------
Tools/c-analyzer/cpython/ignored.tsv | 1 -
4 files changed, 17 insertions(+), 151 deletions(-)
diff --git a/Lib/test/test_free_threading/test_slots.py b/Lib/test/test_free_threading/test_slots.py
index 8357a2a75043b1..a73525e1bebfb4 100644
--- a/Lib/test/test_free_threading/test_slots.py
+++ b/Lib/test/test_free_threading/test_slots.py
@@ -16,18 +16,19 @@ def run_in_threads(targets):
thread.join()
+class Spam:
+ __slots__ = [
+ "eggs",
+ ]
+
+ def __init__(self, initial_value):
+ self.eggs = initial_value
+
+
@threading_helper.requires_working_threading()
class TestSlots(TestCase):
def test_object(self):
- class Spam:
- __slots__ = [
- "eggs",
- ]
-
- def __init__(self, initial_value):
- self.eggs = initial_value
-
spam = Spam(0)
iters = 20_000
@@ -48,44 +49,18 @@ def test_del_object_is_atomic(self):
# removes the attribute atomically, thus avoiding non-sequentially-
# consistent behaviors.
# https://github.com/python/cpython/issues/146270
-
- class Spam:
- __slots__ = [
- "eggs",
- "foo",
- ]
-
- spam = Spam()
- non_seq_cst_behaviour_observed = False
-
- def deleter():
- barrier.wait()
+ def deleter(spam, successes):
try:
del spam.eggs
+ successes.append(True)
except AttributeError:
- pass
- else:
- try:
- del spam.foo
- except AttributeError:
- nonlocal non_seq_cst_behaviour_observed
- non_seq_cst_behaviour_observed = True
- # The fact that the else branch was reached implies that
- # the `del spam.eggs` call was successful. If that were
- # atomic, there is no way for two threads to enter the else
- # branch, therefore it must be that only one thread
- # attempts to `del spam.foo`. Thus, hitting an
- # AttributeError here is non-sequentially-consistent,
- # falsifying the assumption that `del spam.eggs` was
- # atomic. The test fails if this point is reached.
+ successes.append(False)
for _ in range(10):
- spam.eggs = 0
- spam.foo = 0
- barrier = _testcapi.SpinningBarrier(2)
- # threading.Barrier would not create enough contention here
- run_in_threads([deleter, deleter])
- self.assertFalse(non_seq_cst_behaviour_observed)
+ spam = Spam(0)
+ successes = []
+ threading_helper.run_concurrently(deleter, nthreads=4, args=(spam, successes))
+ self.assertEqual(sum(successes), 1)
def test_T_BOOL(self):
spam_old = _testcapi._test_structmembersType_OldAPI()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
index 339697d6f3132e..46c292e183e0fd 100644
--- a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-20-15-25-55.gh-issue-146270.qZYfyc.rst
@@ -1 +1 @@
-Fix a sequential consistency bug in ``structmember.c`` and add ``_testcapi.SpinningBarrier`` to support the new test.
+Fix a sequential consistency bug in ``structmember.c``.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 35f251e3c86971..3ebe4ceea6a72e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2642,108 +2642,6 @@ test_soft_deprecated_macros(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)
Py_RETURN_NONE;
}
-/**
- * A spinning barrier is a multithreading barrier similar to threading.Barrier,
- * except that it never parks threads that are waiting on the barrier.
- *
- * This is useful in scenarios where it is desirable to increase contention on
- * the code that follows the barrier. For instance, consider this test:
- *
- * def test_my_method_is_atomic():
- * x = MyClass()
- * b = _testcapi.SpinningBarrier()
- *
- * def thread():
- * b.wait()
- * x.my_method()
- *
- * for _ in range(1_000):
- * threads = [Thread(target=thread), Thread(target=thread)]
- * for t in threads: t.start()
- * for t in threads: t.join()
- *
- * It can be desirable (and sometimes necessary) to increase the contention
- * on x's internal data structure by avoiding threads parking.
- * Here, not parking may become necessary when the code in my_method() is so
- * short that contention-related code paths are never exercised otherwise.
- *
- * It is roughly equivalent to this Python class:
- *
- * class SpinningBarrier:
- * def __init__(self, parties: int):
- * self.parties = AtomicInt(parties) # if only we had atomic integers
- *
- * def wait(self):
- * v = self.parties.decrement_and_get()
- * while True:
- * if v < 0:
- * raise ValueError("wait was called too many times")
- * if v == 0:
- * return
- * v = self.parties.get()
- *
- */
-
-typedef struct {
- PyObject_HEAD
- int parties;
-} SpinningBarrier;
-
-int
-SpinningBarrier_init(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- int parties = 0;
- const char *kwlist[] = {"parties", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", (char **)kwlist, &parties)) {
- return -1;
- }
- if (parties <= 0) {
- PyErr_SetString(PyExc_ValueError, "parties must be greater than zero");
- return -1;
- }
-
- SpinningBarrier *self_b = (SpinningBarrier *) self;
- self_b->parties = parties;
-
- return 0;
-}
-
-PyObject *
-SpinningBarrier_wait(PyObject *self, PyObject *Py_UNUSED(args))
-{
- SpinningBarrier *self_b = (SpinningBarrier *) self;
- const long decremented = _Py_atomic_add_int(&self_b->parties, -1) - 1;
- long v = decremented;
- while (1) {
- if (v < 0) {
- PyErr_SetString(PyExc_ValueError, "wait was called too many times");
- return NULL;
- }
- if (v == 0) {
- return PyLong_FromLong(decremented);
- }
- v = _Py_atomic_load_int_relaxed(&self_b->parties);
- if (PyErr_CheckSignals()) {
- return NULL;
- }
- }
-}
-
-static PyMethodDef SpinningBarrier_methods[] = {
- {"wait", SpinningBarrier_wait, METH_NOARGS},
- {NULL, NULL},
-};
-
-static PyTypeObject SpinningBarrier_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "SpinningBarrier",
- .tp_basicsize = sizeof(SpinningBarrier),
- .tp_new = PyType_GenericNew,
- .tp_free = PyObject_Free,
- .tp_init = &SpinningBarrier_init,
- .tp_methods = SpinningBarrier_methods,
-};
-
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
@@ -3471,12 +3369,6 @@ _testcapi_exec(PyObject *m)
Py_INCREF(&MethStatic_Type);
PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type);
- if (PyType_Ready(&SpinningBarrier_Type) < 0) {
- return -1;
- }
- Py_INCREF(&SpinningBarrier_Type);
- PyModule_AddObject(m, "SpinningBarrier", (PyObject *)&SpinningBarrier_Type);
-
PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX));
PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN));
PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX));
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index 4933a08aca429e..d2489387f46caa 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -542,7 +542,6 @@ Modules/_testcapimodule.c - meth_class_methods -
Modules/_testcapimodule.c - meth_instance_methods -
Modules/_testcapimodule.c - meth_static_methods -
Modules/_testcapimodule.c - ml -
-Modules/_testcapimodule.c - SpinningBarrier_Type -
Modules/_testcapimodule.c - str1 -
Modules/_testcapimodule.c - str2 -
Modules/_testcapimodule.c - test_c_thread -
pFad - Phonifier reborn
Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy