From afd3eff1175e09c479e5a30c5494cea94a3f5381 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 16 Dec 2025 15:10:09 -0500 Subject: [PATCH 1/4] gh-129068: Make range iterators thread-safe Now that we specialize range iteration in the interpreter for the common case where the iterator has only one reference, there's not a significant performance cost to making the iteration thread-safe. --- Objects/clinic/rangeobject.c.h | 135 ++++++++++++++++ Objects/rangeobject.c | 174 ++++++++++++++------- Tools/tsan/suppressions_free_threading.txt | 6 - 3 files changed, 254 insertions(+), 61 deletions(-) create mode 100644 Objects/clinic/rangeobject.c.h diff --git a/Objects/clinic/rangeobject.c.h b/Objects/clinic/rangeobject.c.h new file mode 100644 index 00000000000000..aff8af2c7a64cb --- /dev/null +++ b/Objects/clinic/rangeobject.c.h @@ -0,0 +1,135 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + +PyDoc_STRVAR(range_iterator___length_hint____doc__, +"__length_hint__($self, /)\n" +"--\n" +"\n" +"Private method returning an estimate of len(list(it))."); + +#define RANGE_ITERATOR___LENGTH_HINT___METHODDEF \ + {"__length_hint__", (PyCFunction)range_iterator___length_hint__, METH_NOARGS, range_iterator___length_hint____doc__}, + +static PyObject * +range_iterator___length_hint___impl(_PyRangeIterObject *self); + +static PyObject * +range_iterator___length_hint__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = range_iterator___length_hint___impl((_PyRangeIterObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(range_iterator___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Return state information for pickling."); + +#define RANGE_ITERATOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)range_iterator___reduce__, METH_NOARGS, range_iterator___reduce____doc__}, + +static PyObject * +range_iterator___reduce___impl(_PyRangeIterObject *self); + +static PyObject * +range_iterator___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = range_iterator___reduce___impl((_PyRangeIterObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(range_iterator___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n" +"Set state information for unpickling."); + +#define RANGE_ITERATOR___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)range_iterator___setstate__, METH_O, range_iterator___setstate____doc__}, + +static PyObject * +range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state); + +static PyObject * +range_iterator___setstate__(PyObject *self, PyObject *state) +{ + PyObject *return_value = NULL; + + return_value = range_iterator___setstate___impl((_PyRangeIterObject *)self, state); + + return return_value; +} + +PyDoc_STRVAR(longrange_iterator___length_hint____doc__, +"__length_hint__($self, /)\n" +"--\n" +"\n" +"Private method returning an estimate of len(list(it))."); + +#define LONGRANGE_ITERATOR___LENGTH_HINT___METHODDEF \ + {"__length_hint__", (PyCFunction)longrange_iterator___length_hint__, METH_NOARGS, longrange_iterator___length_hint____doc__}, + +static PyObject * +longrange_iterator___length_hint___impl(longrangeiterobject *self); + +static PyObject * +longrange_iterator___length_hint__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return longrange_iterator___length_hint___impl((longrangeiterobject *)self); +} + +PyDoc_STRVAR(longrange_iterator___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Return state information for pickling."); + +#define LONGRANGE_ITERATOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)longrange_iterator___reduce__, METH_NOARGS, longrange_iterator___reduce____doc__}, + +static PyObject * +longrange_iterator___reduce___impl(longrangeiterobject *self); + +static PyObject * +longrange_iterator___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return longrange_iterator___reduce___impl((longrangeiterobject *)self); +} + +PyDoc_STRVAR(longrange_iterator___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n" +"Set state information for unpickling."); + +#define LONGRANGE_ITERATOR___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)longrange_iterator___setstate__, METH_O, longrange_iterator___setstate____doc__}, + +static PyObject * +longrange_iterator___setstate___impl(longrangeiterobject *self, + PyObject *state); + +static PyObject * +longrange_iterator___setstate__(PyObject *self, PyObject *state) +{ + PyObject *return_value = NULL; + + return_value = longrange_iterator___setstate___impl((longrangeiterobject *)self, state); + + return return_value; +} +/*[clinic end generated code: output=3901cac5f53f222e input=a9049054013a1b77]*/ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index e93346fb27703f..29b5b6b12f60d3 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -9,6 +9,21 @@ #include "pycore_range.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() +typedef struct { + PyObject_HEAD + PyObject *start; + PyObject *step; + PyObject *len; +} longrangeiterobject; + +/*[clinic input] +class range_iterator "_PyRangeIterObject *" "&PyRangeIter_Type" +class longrange_iterator "longrangeiterobject *" "&PyLongRangeIter_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7d97a63d1cfa6b3]*/ + +#include "clinic/rangeobject.c.h" + /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -830,41 +845,55 @@ PyTypeObject PyRange_Type = { static PyObject * rangeiter_next(PyObject *op) { + PyObject *ret = NULL; + Py_BEGIN_CRITICAL_SECTION(op); _PyRangeIterObject *r = (_PyRangeIterObject*)op; if (r->len > 0) { long result = r->start; r->start = result + r->step; r->len--; - return PyLong_FromLong(result); + ret = PyLong_FromLong(result); } - return NULL; + Py_END_CRITICAL_SECTION(); + return ret; } +/*[clinic input] +@critical_section +range_iterator.__length_hint__ + +Private method returning an estimate of len(list(it)). +[clinic start generated code]*/ + static PyObject * -rangeiter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) +range_iterator___length_hint___impl(_PyRangeIterObject *self) +/*[clinic end generated code: output=e1cffa4f1e04271b input=ae170413369cd502]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; - return PyLong_FromLong(r->len); + return PyLong_FromLong(self->len); } -PyDoc_STRVAR(length_hint_doc, - "Private method returning an estimate of len(list(it))."); +/*[clinic input] +@critical_section +range_iterator.__reduce__ + +Return state information for pickling. +[clinic start generated code]*/ static PyObject * -rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) +range_iterator___reduce___impl(_PyRangeIterObject *self) +/*[clinic end generated code: output=a462cc821bf3c94e input=ec043bf3db63c113]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; PyObject *start=NULL, *stop=NULL, *step=NULL; PyObject *range; /* create a range object for pickling */ - start = PyLong_FromLong(r->start); + start = PyLong_FromLong(self->start); if (start == NULL) goto err; - stop = PyLong_FromLong(r->start + r->len * r->step); + stop = PyLong_FromLong(self->start + self->len * self->step); if (stop == NULL) goto err; - step = PyLong_FromLong(r->step); + step = PyLong_FromLong(self->step); if (step == NULL) goto err; range = (PyObject*)make_range_object(&PyRange_Type, @@ -881,20 +910,30 @@ rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) return NULL; } +/*[clinic input] +@critical_section +range_iterator.__setstate__ + + state: object + / + +Set state information for unpickling. +[clinic start generated code]*/ + static PyObject * -rangeiter_setstate(PyObject *op, PyObject *state) +range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state) +/*[clinic end generated code: output=8c0cbca5b07a30a3 input=acd092f19666fd2e]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; long index = PyLong_AsLong(state); if (index == -1 && PyErr_Occurred()) return NULL; /* silently clip the index value */ if (index < 0) index = 0; - else if (index > r->len) - index = r->len; /* exhausted iterator */ - r->start += index * r->step; - r->len -= index; + else if (index > self->len) + index = self->len; /* exhausted iterator */ + self->start += index * self->step; + self->len -= index; Py_RETURN_NONE; } @@ -904,13 +943,10 @@ rangeiter_dealloc(PyObject *self) _Py_FREELIST_FREE(range_iters, (_PyRangeIterObject *)self, PyObject_Free); } -PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); -PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - static PyMethodDef rangeiter_methods[] = { - {"__length_hint__", rangeiter_len, METH_NOARGS, length_hint_doc}, - {"__reduce__", rangeiter_reduce, METH_NOARGS, reduce_doc}, - {"__setstate__", rangeiter_setstate, METH_O, setstate_doc}, + RANGE_ITERATOR___LENGTH_HINT___METHODDEF + RANGE_ITERATOR___REDUCE___METHODDEF + RANGE_ITERATOR___SETSTATE___METHODDEF {NULL, NULL} /* sentinel */ }; @@ -995,42 +1031,49 @@ fast_range_iter(long start, long stop, long step, long len) return (PyObject *)it; } -typedef struct { - PyObject_HEAD - PyObject *start; - PyObject *step; - PyObject *len; -} longrangeiterobject; +/*[clinic input] +@critical_section +longrange_iterator.__length_hint__ + +Private method returning an estimate of len(list(it)). +[clinic start generated code]*/ static PyObject * -longrangeiter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) +longrange_iterator___length_hint___impl(longrangeiterobject *self) +/*[clinic end generated code: output=1890e941c1688fcd input=0dd7a785a3ee9e9a]*/ { - longrangeiterobject *r = (longrangeiterobject*)op; - Py_INCREF(r->len); - return r->len; + Py_INCREF(self->len); + return self->len; } +/*[clinic input] +@critical_section +longrange_iterator.__reduce__ + +Return state information for pickling. +[clinic start generated code]*/ + static PyObject * -longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) +longrange_iterator___reduce___impl(longrangeiterobject *self) +/*[clinic end generated code: output=6efcfea6587678cd input=f73e1a6449166649]*/ { - longrangeiterobject *r = (longrangeiterobject*)op; PyObject *product, *stop=NULL; PyObject *range; /* create a range object for pickling. Must calculate the "stop" value */ - product = PyNumber_Multiply(r->len, r->step); + product = PyNumber_Multiply(self->len, self->step); if (product == NULL) return NULL; - stop = PyNumber_Add(r->start, product); + stop = PyNumber_Add(self->start, product); Py_DECREF(product); if (stop == NULL) return NULL; range = (PyObject*)make_range_object(&PyRange_Type, - Py_NewRef(r->start), stop, Py_NewRef(r->step)); + Py_NewRef(self->start), stop, Py_NewRef(self->step)); if (range == NULL) { - Py_DECREF(r->start); + Py_DECREF(self->start); Py_DECREF(stop); - Py_DECREF(r->step); + Py_DECREF(self->step); return NULL; } @@ -1039,15 +1082,26 @@ longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) range, Py_None); } +/*[clinic input] +@critical_section +longrange_iterator.__setstate__ + + state: object + / + +Set state information for unpickling. +[clinic start generated code]*/ + static PyObject * -longrangeiter_setstate(PyObject *op, PyObject *state) +longrange_iterator___setstate___impl(longrangeiterobject *self, + PyObject *state) +/*[clinic end generated code: output=0ad8528a4b723cd0 input=84c0bb455543ee24]*/ { if (!PyLong_CheckExact(state)) { PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state); return NULL; } - longrangeiterobject *r = (longrangeiterobject*)op; PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp; @@ -1059,35 +1113,35 @@ longrangeiter_setstate(PyObject *op, PyObject *state) state = zero; } else { - cmp = PyObject_RichCompareBool(r->len, state, Py_LT); + cmp = PyObject_RichCompareBool(self->len, state, Py_LT); if (cmp < 0) return NULL; if (cmp > 0) - state = r->len; + state = self->len; } - PyObject *product = PyNumber_Multiply(state, r->step); + PyObject *product = PyNumber_Multiply(state, self->step); if (product == NULL) return NULL; - PyObject *new_start = PyNumber_Add(r->start, product); + PyObject *new_start = PyNumber_Add(self->start, product); Py_DECREF(product); if (new_start == NULL) return NULL; - PyObject *new_len = PyNumber_Subtract(r->len, state); + PyObject *new_len = PyNumber_Subtract(self->len, state); if (new_len == NULL) { Py_DECREF(new_start); return NULL; } - PyObject *tmp = r->start; - r->start = new_start; - Py_SETREF(r->len, new_len); + PyObject *tmp = self->start; + self->start = new_start; + Py_SETREF(self->len, new_len); Py_DECREF(tmp); Py_RETURN_NONE; } static PyMethodDef longrangeiter_methods[] = { - {"__length_hint__", longrangeiter_len, METH_NOARGS, length_hint_doc}, - {"__reduce__", longrangeiter_reduce, METH_NOARGS, reduce_doc}, - {"__setstate__", longrangeiter_setstate, METH_O, setstate_doc}, + LONGRANGE_ITERATOR___LENGTH_HINT___METHODDEF + LONGRANGE_ITERATOR___REDUCE___METHODDEF + LONGRANGE_ITERATOR___SETSTATE___METHODDEF {NULL, NULL} /* sentinel */ }; @@ -1102,7 +1156,7 @@ longrangeiter_dealloc(PyObject *op) } static PyObject * -longrangeiter_next(PyObject *op) +longrangeiter_next_lock_held(PyObject *op) { longrangeiterobject *r = (longrangeiterobject*)op; if (PyObject_RichCompareBool(r->len, _PyLong_GetZero(), Py_GT) != 1) @@ -1123,6 +1177,16 @@ longrangeiter_next(PyObject *op) return result; } +static PyObject * +longrangeiter_next(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = longrangeiter_next_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + PyTypeObject PyLongRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "longrange_iterator", /* tp_name */ diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 404c30157362aa..28c50ff4b16a37 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -20,18 +20,12 @@ race_top:_PyObject_TryGetInstanceAttribute race_top:PyUnstable_InterpreterFrame_GetLine race_top:write_thread_id -# gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading) -race_top:rangeiter_next - # gh-129748: test.test_free_threading.test_slots.TestSlots.test_object race_top:mi_block_set_nextx # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create -# Range iteration is not thread-safe yet (issue #129068) -race_top:rangeiter_next - # List resizing happens through different paths ending in memcpy or memmove # (for efficiency), which will probably need to rewritten as explicit loops # of ptr-sized copies to be thread-safe. (Issue #129069) From 366d88c0e136aa7556f2f6b97ea29ac3f173a85f Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Wed, 17 Dec 2025 10:49:08 -0500 Subject: [PATCH 2/4] Blurb --- .../2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst new file mode 100644 index 00000000000000..16b19524cd4057 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst @@ -0,0 +1,2 @@ +Make concurrent iteration over the same range iterator thread-safe in the +free threading build. From 3287a205d5eca97eebd621feb56e02a4a1df42f9 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Wed, 17 Dec 2025 10:57:32 -0500 Subject: [PATCH 3/4] Update generated clinic files --- Objects/clinic/rangeobject.c.h | 22 +++++++++++++++++++--- Objects/rangeobject.c | 8 ++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Objects/clinic/rangeobject.c.h b/Objects/clinic/rangeobject.c.h index aff8af2c7a64cb..f8be7701f78b7a 100644 --- a/Objects/clinic/rangeobject.c.h +++ b/Objects/clinic/rangeobject.c.h @@ -69,7 +69,9 @@ range_iterator___setstate__(PyObject *self, PyObject *state) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = range_iterator___setstate___impl((_PyRangeIterObject *)self, state); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -89,7 +91,13 @@ longrange_iterator___length_hint___impl(longrangeiterobject *self); static PyObject * longrange_iterator___length_hint__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return longrange_iterator___length_hint___impl((longrangeiterobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = longrange_iterator___length_hint___impl((longrangeiterobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(longrange_iterator___reduce____doc__, @@ -107,7 +115,13 @@ longrange_iterator___reduce___impl(longrangeiterobject *self); static PyObject * longrange_iterator___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return longrange_iterator___reduce___impl((longrangeiterobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = longrange_iterator___reduce___impl((longrangeiterobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(longrange_iterator___setstate____doc__, @@ -128,8 +142,10 @@ longrange_iterator___setstate__(PyObject *self, PyObject *state) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = longrange_iterator___setstate___impl((longrangeiterobject *)self, state); + Py_END_CRITICAL_SECTION(); return return_value; } -/*[clinic end generated code: output=3901cac5f53f222e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=759305b89302c30c input=a9049054013a1b77]*/ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 29b5b6b12f60d3..b01ef68d06fc37 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -922,7 +922,7 @@ Set state information for unpickling. static PyObject * range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state) -/*[clinic end generated code: output=8c0cbca5b07a30a3 input=acd092f19666fd2e]*/ +/*[clinic end generated code: output=8c0cbca5b07a30a3 input=230f74fae1cb5008]*/ { long index = PyLong_AsLong(state); if (index == -1 && PyErr_Occurred()) @@ -1040,7 +1040,7 @@ Private method returning an estimate of len(list(it)). static PyObject * longrange_iterator___length_hint___impl(longrangeiterobject *self) -/*[clinic end generated code: output=1890e941c1688fcd input=0dd7a785a3ee9e9a]*/ +/*[clinic end generated code: output=1890e941c1688fcd input=eef1908ae4759fb2]*/ { Py_INCREF(self->len); return self->len; @@ -1055,7 +1055,7 @@ Return state information for pickling. static PyObject * longrange_iterator___reduce___impl(longrangeiterobject *self) -/*[clinic end generated code: output=6efcfea6587678cd input=f73e1a6449166649]*/ +/*[clinic end generated code: output=6efcfea6587678cd input=21302109df76aac9]*/ { PyObject *product, *stop=NULL; PyObject *range; @@ -1095,7 +1095,7 @@ Set state information for unpickling. static PyObject * longrange_iterator___setstate___impl(longrangeiterobject *self, PyObject *state) -/*[clinic end generated code: output=0ad8528a4b723cd0 input=84c0bb455543ee24]*/ +/*[clinic end generated code: output=0ad8528a4b723cd0 input=7304c65ba48035ea]*/ { if (!PyLong_CheckExact(state)) { PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state); From c766b4e82e81ee23457f53b50b0a552fa88223c6 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Wed, 17 Dec 2025 12:12:13 -0500 Subject: [PATCH 4/4] Use 'self as r: self' to reduce diff size --- Objects/clinic/rangeobject.c.h | 51 +++++++++++----------- Objects/rangeobject.c | 79 ++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/Objects/clinic/rangeobject.c.h b/Objects/clinic/rangeobject.c.h index f8be7701f78b7a..d9142eddde4b17 100644 --- a/Objects/clinic/rangeobject.c.h +++ b/Objects/clinic/rangeobject.c.h @@ -14,15 +14,15 @@ PyDoc_STRVAR(range_iterator___length_hint____doc__, {"__length_hint__", (PyCFunction)range_iterator___length_hint__, METH_NOARGS, range_iterator___length_hint____doc__}, static PyObject * -range_iterator___length_hint___impl(_PyRangeIterObject *self); +range_iterator___length_hint___impl(_PyRangeIterObject *r); static PyObject * -range_iterator___length_hint__(PyObject *self, PyObject *Py_UNUSED(ignored)) +range_iterator___length_hint__(PyObject *r, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = range_iterator___length_hint___impl((_PyRangeIterObject *)self); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___length_hint___impl((_PyRangeIterObject *)r); Py_END_CRITICAL_SECTION(); return return_value; @@ -38,15 +38,15 @@ PyDoc_STRVAR(range_iterator___reduce____doc__, {"__reduce__", (PyCFunction)range_iterator___reduce__, METH_NOARGS, range_iterator___reduce____doc__}, static PyObject * -range_iterator___reduce___impl(_PyRangeIterObject *self); +range_iterator___reduce___impl(_PyRangeIterObject *r); static PyObject * -range_iterator___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +range_iterator___reduce__(PyObject *r, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = range_iterator___reduce___impl((_PyRangeIterObject *)self); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___reduce___impl((_PyRangeIterObject *)r); Py_END_CRITICAL_SECTION(); return return_value; @@ -62,15 +62,15 @@ PyDoc_STRVAR(range_iterator___setstate____doc__, {"__setstate__", (PyCFunction)range_iterator___setstate__, METH_O, range_iterator___setstate____doc__}, static PyObject * -range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state); +range_iterator___setstate___impl(_PyRangeIterObject *r, PyObject *state); static PyObject * -range_iterator___setstate__(PyObject *self, PyObject *state) +range_iterator___setstate__(PyObject *r, PyObject *state) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = range_iterator___setstate___impl((_PyRangeIterObject *)self, state); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___setstate___impl((_PyRangeIterObject *)r, state); Py_END_CRITICAL_SECTION(); return return_value; @@ -86,15 +86,15 @@ PyDoc_STRVAR(longrange_iterator___length_hint____doc__, {"__length_hint__", (PyCFunction)longrange_iterator___length_hint__, METH_NOARGS, longrange_iterator___length_hint____doc__}, static PyObject * -longrange_iterator___length_hint___impl(longrangeiterobject *self); +longrange_iterator___length_hint___impl(longrangeiterobject *r); static PyObject * -longrange_iterator___length_hint__(PyObject *self, PyObject *Py_UNUSED(ignored)) +longrange_iterator___length_hint__(PyObject *r, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = longrange_iterator___length_hint___impl((longrangeiterobject *)self); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___length_hint___impl((longrangeiterobject *)r); Py_END_CRITICAL_SECTION(); return return_value; @@ -110,15 +110,15 @@ PyDoc_STRVAR(longrange_iterator___reduce____doc__, {"__reduce__", (PyCFunction)longrange_iterator___reduce__, METH_NOARGS, longrange_iterator___reduce____doc__}, static PyObject * -longrange_iterator___reduce___impl(longrangeiterobject *self); +longrange_iterator___reduce___impl(longrangeiterobject *r); static PyObject * -longrange_iterator___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +longrange_iterator___reduce__(PyObject *r, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = longrange_iterator___reduce___impl((longrangeiterobject *)self); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___reduce___impl((longrangeiterobject *)r); Py_END_CRITICAL_SECTION(); return return_value; @@ -134,18 +134,17 @@ PyDoc_STRVAR(longrange_iterator___setstate____doc__, {"__setstate__", (PyCFunction)longrange_iterator___setstate__, METH_O, longrange_iterator___setstate____doc__}, static PyObject * -longrange_iterator___setstate___impl(longrangeiterobject *self, - PyObject *state); +longrange_iterator___setstate___impl(longrangeiterobject *r, PyObject *state); static PyObject * -longrange_iterator___setstate__(PyObject *self, PyObject *state) +longrange_iterator___setstate__(PyObject *r, PyObject *state) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - return_value = longrange_iterator___setstate___impl((longrangeiterobject *)self, state); + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___setstate___impl((longrangeiterobject *)r, state); Py_END_CRITICAL_SECTION(); return return_value; } -/*[clinic end generated code: output=759305b89302c30c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=719c0e4c81fe0f4a input=a9049054013a1b77]*/ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index b01ef68d06fc37..55b7f108730728 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -861,39 +861,41 @@ rangeiter_next(PyObject *op) /*[clinic input] @critical_section range_iterator.__length_hint__ + self as r: self(type="_PyRangeIterObject *") Private method returning an estimate of len(list(it)). [clinic start generated code]*/ static PyObject * -range_iterator___length_hint___impl(_PyRangeIterObject *self) -/*[clinic end generated code: output=e1cffa4f1e04271b input=ae170413369cd502]*/ +range_iterator___length_hint___impl(_PyRangeIterObject *r) +/*[clinic end generated code: output=9ba6f22b1fc23dcc input=e3eb311e99d76e43]*/ { - return PyLong_FromLong(self->len); + return PyLong_FromLong(r->len); } /*[clinic input] @critical_section range_iterator.__reduce__ + self as r: self(type="_PyRangeIterObject *") Return state information for pickling. [clinic start generated code]*/ static PyObject * -range_iterator___reduce___impl(_PyRangeIterObject *self) -/*[clinic end generated code: output=a462cc821bf3c94e input=ec043bf3db63c113]*/ +range_iterator___reduce___impl(_PyRangeIterObject *r) +/*[clinic end generated code: output=c44d53750c388415 input=75a25b7076dc2c54]*/ { PyObject *start=NULL, *stop=NULL, *step=NULL; PyObject *range; /* create a range object for pickling */ - start = PyLong_FromLong(self->start); + start = PyLong_FromLong(r->start); if (start == NULL) goto err; - stop = PyLong_FromLong(self->start + self->len * self->step); + stop = PyLong_FromLong(r->start + r->len * r->step); if (stop == NULL) goto err; - step = PyLong_FromLong(self->step); + step = PyLong_FromLong(r->step); if (step == NULL) goto err; range = (PyObject*)make_range_object(&PyRange_Type, @@ -913,7 +915,7 @@ range_iterator___reduce___impl(_PyRangeIterObject *self) /*[clinic input] @critical_section range_iterator.__setstate__ - + self as r: self(type="_PyRangeIterObject *") state: object / @@ -921,8 +923,8 @@ Set state information for unpickling. [clinic start generated code]*/ static PyObject * -range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state) -/*[clinic end generated code: output=8c0cbca5b07a30a3 input=230f74fae1cb5008]*/ +range_iterator___setstate___impl(_PyRangeIterObject *r, PyObject *state) +/*[clinic end generated code: output=464b3cbafc2e3562 input=c8c84fab2519d200]*/ { long index = PyLong_AsLong(state); if (index == -1 && PyErr_Occurred()) @@ -930,10 +932,10 @@ range_iterator___setstate___impl(_PyRangeIterObject *self, PyObject *state) /* silently clip the index value */ if (index < 0) index = 0; - else if (index > self->len) - index = self->len; /* exhausted iterator */ - self->start += index * self->step; - self->len -= index; + else if (index > r->len) + index = r->len; /* exhausted iterator */ + r->start += index * r->step; + r->len -= index; Py_RETURN_NONE; } @@ -1034,46 +1036,48 @@ fast_range_iter(long start, long stop, long step, long len) /*[clinic input] @critical_section longrange_iterator.__length_hint__ + self as r: self(type="longrangeiterobject *") Private method returning an estimate of len(list(it)). [clinic start generated code]*/ static PyObject * -longrange_iterator___length_hint___impl(longrangeiterobject *self) -/*[clinic end generated code: output=1890e941c1688fcd input=eef1908ae4759fb2]*/ +longrange_iterator___length_hint___impl(longrangeiterobject *r) +/*[clinic end generated code: output=e1bce24da7e8bfde input=ba94b050d940411e]*/ { - Py_INCREF(self->len); - return self->len; + Py_INCREF(r->len); + return r->len; } /*[clinic input] @critical_section longrange_iterator.__reduce__ + self as r: self(type="longrangeiterobject *") Return state information for pickling. [clinic start generated code]*/ static PyObject * -longrange_iterator___reduce___impl(longrangeiterobject *self) -/*[clinic end generated code: output=6efcfea6587678cd input=21302109df76aac9]*/ +longrange_iterator___reduce___impl(longrangeiterobject *r) +/*[clinic end generated code: output=0077f94ae2a4e99a input=2e8930e897ace086]*/ { PyObject *product, *stop=NULL; PyObject *range; /* create a range object for pickling. Must calculate the "stop" value */ - product = PyNumber_Multiply(self->len, self->step); + product = PyNumber_Multiply(r->len, r->step); if (product == NULL) return NULL; - stop = PyNumber_Add(self->start, product); + stop = PyNumber_Add(r->start, product); Py_DECREF(product); if (stop == NULL) return NULL; range = (PyObject*)make_range_object(&PyRange_Type, - Py_NewRef(self->start), stop, Py_NewRef(self->step)); + Py_NewRef(r->start), stop, Py_NewRef(r->step)); if (range == NULL) { - Py_DECREF(self->start); + Py_DECREF(r->start); Py_DECREF(stop); - Py_DECREF(self->step); + Py_DECREF(r->step); return NULL; } @@ -1085,7 +1089,7 @@ longrange_iterator___reduce___impl(longrangeiterobject *self) /*[clinic input] @critical_section longrange_iterator.__setstate__ - + self as r: self(type="longrangeiterobject *") state: object / @@ -1093,9 +1097,8 @@ Set state information for unpickling. [clinic start generated code]*/ static PyObject * -longrange_iterator___setstate___impl(longrangeiterobject *self, - PyObject *state) -/*[clinic end generated code: output=0ad8528a4b723cd0 input=7304c65ba48035ea]*/ +longrange_iterator___setstate___impl(longrangeiterobject *r, PyObject *state) +/*[clinic end generated code: output=870787f0574f0da4 input=8b116de3018de824]*/ { if (!PyLong_CheckExact(state)) { PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state); @@ -1113,27 +1116,27 @@ longrange_iterator___setstate___impl(longrangeiterobject *self, state = zero; } else { - cmp = PyObject_RichCompareBool(self->len, state, Py_LT); + cmp = PyObject_RichCompareBool(r->len, state, Py_LT); if (cmp < 0) return NULL; if (cmp > 0) - state = self->len; + state = r->len; } - PyObject *product = PyNumber_Multiply(state, self->step); + PyObject *product = PyNumber_Multiply(state, r->step); if (product == NULL) return NULL; - PyObject *new_start = PyNumber_Add(self->start, product); + PyObject *new_start = PyNumber_Add(r->start, product); Py_DECREF(product); if (new_start == NULL) return NULL; - PyObject *new_len = PyNumber_Subtract(self->len, state); + PyObject *new_len = PyNumber_Subtract(r->len, state); if (new_len == NULL) { Py_DECREF(new_start); return NULL; } - PyObject *tmp = self->start; - self->start = new_start; - Py_SETREF(self->len, new_len); + PyObject *tmp = r->start; + r->start = new_start; + Py_SETREF(r->len, new_len); Py_DECREF(tmp); Py_RETURN_NONE; }