forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-117657: Fix itertools.count thread safety (python#119268)
Fix itertools.count in free-threading mode
- Loading branch information
Showing
3 changed files
with
54 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
#include "Python.h" | ||
#include "pycore_call.h" // _PyObject_CallNoArgs() | ||
#include "pycore_ceval.h" // _PyEval_GetBuiltin() | ||
#include "pycore_long.h" // _PyLong_GetZero() | ||
#include "pycore_moduleobject.h" // _PyModule_GetState() | ||
#include "pycore_typeobject.h" // _PyType_GetModuleState() | ||
#include "pycore_object.h" // _PyObject_GC_TRACK() | ||
#include "pycore_tuple.h" // _PyTuple_ITEMS() | ||
#include "pycore_call.h" // _PyObject_CallNoArgs() | ||
#include "pycore_ceval.h" // _PyEval_GetBuiltin() | ||
#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() | ||
#include "pycore_long.h" // _PyLong_GetZero() | ||
#include "pycore_moduleobject.h" // _PyModule_GetState() | ||
#include "pycore_typeobject.h" // _PyType_GetModuleState() | ||
#include "pycore_object.h" // _PyObject_GC_TRACK() | ||
#include "pycore_tuple.h" // _PyTuple_ITEMS() | ||
|
||
#include <stddef.h> // offsetof() | ||
#include <stddef.h> // offsetof() | ||
|
||
/* Itertools module written and maintained | ||
by Raymond D. Hettinger <[email protected]> | ||
|
@@ -3254,7 +3255,7 @@ fast_mode: when cnt an integer < PY_SSIZE_T_MAX and no step is specified. | |
assert(cnt != PY_SSIZE_T_MAX && long_cnt == NULL && long_step==PyLong(1)); | ||
Advances with: cnt += 1 | ||
When count hits Y_SSIZE_T_MAX, switch to slow_mode. | ||
When count hits PY_SSIZE_T_MAX, switch to slow_mode. | ||
slow_mode: when cnt == PY_SSIZE_T_MAX, step is not int(1), or cnt is a float. | ||
|
@@ -3403,9 +3404,30 @@ count_nextlong(countobject *lz) | |
static PyObject * | ||
count_next(countobject *lz) | ||
{ | ||
#ifndef Py_GIL_DISABLED | ||
if (lz->cnt == PY_SSIZE_T_MAX) | ||
return count_nextlong(lz); | ||
return PyLong_FromSsize_t(lz->cnt++); | ||
#else | ||
// free-threading version | ||
// fast mode uses compare-exchange loop | ||
// slow mode uses a critical section | ||
PyObject *returned; | ||
Py_ssize_t cnt; | ||
|
||
cnt = _Py_atomic_load_ssize_relaxed(&lz->cnt); | ||
for (;;) { | ||
if (cnt == PY_SSIZE_T_MAX) { | ||
Py_BEGIN_CRITICAL_SECTION(lz); | ||
returned = count_nextlong(lz); | ||
Py_END_CRITICAL_SECTION(); | ||
return returned; | ||
} | ||
if (_Py_atomic_compare_exchange_ssize(&lz->cnt, &cnt, cnt + 1)) { | ||
return PyLong_FromSsize_t(cnt); | ||
} | ||
} | ||
#endif | ||
} | ||
|
||
static PyObject * | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters