Skip to content

Commit 459638f

Browse files
committed
Merge branch 'main' into gh-110481-inter-thread-queue
2 parents bc68b9a + fedbf77 commit 459638f

30 files changed

+1482
-1188
lines changed

Doc/c-api/intro.rst

+6-5
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ complete listing.
148148
worse performances (due to increased code size for example). The compiler is
149149
usually smarter than the developer for the cost/benefit analysis.
150150

151-
If Python is :ref:`built in debug mode <debug-build>` (if the ``Py_DEBUG``
151+
If Python is :ref:`built in debug mode <debug-build>` (if the :c:macro:`Py_DEBUG`
152152
macro is defined), the :c:macro:`Py_ALWAYS_INLINE` macro does nothing.
153153

154154
It must be specified before the function return type. Usage::
@@ -812,12 +812,14 @@ available that support tracing of reference counts, debugging the memory
812812
allocator, or low-level profiling of the main interpreter loop. Only the most
813813
frequently used builds will be described in the remainder of this section.
814814

815-
Compiling the interpreter with the :c:macro:`Py_DEBUG` macro defined produces
815+
.. c:macro:: Py_DEBUG
816+
817+
Compiling the interpreter with the :c:macro:`!Py_DEBUG` macro defined produces
816818
what is generally meant by :ref:`a debug build of Python <debug-build>`.
817-
:c:macro:`Py_DEBUG` is enabled in the Unix build by adding
819+
:c:macro:`!Py_DEBUG` is enabled in the Unix build by adding
818820
:option:`--with-pydebug` to the :file:`./configure` command.
819821
It is also implied by the presence of the
820-
not-Python-specific :c:macro:`_DEBUG` macro. When :c:macro:`Py_DEBUG` is enabled
822+
not-Python-specific :c:macro:`!_DEBUG` macro. When :c:macro:`!Py_DEBUG` is enabled
821823
in the Unix build, compiler optimization is disabled.
822824

823825
In addition to the reference count debugging described below, extra checks are
@@ -832,4 +834,3 @@ after every statement run by the interpreter.)
832834

833835
Please refer to :file:`Misc/SpecialBuilds.txt` in the Python source distribution
834836
for more detailed information.
835-

Doc/library/enum.rst

+1-3
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,7 @@ Data Types
534534
>>> list(purple)
535535
[<Color.RED: 1>, <Color.BLUE: 4>]
536536

537-
.. versionchanged:: 3.11
538-
539-
Aliases are no longer returned during iteration.
537+
.. versionadded:: 3.11
540538

541539
.. method:: __len__(self):
542540

Doc/library/test.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,9 @@ The :mod:`test.support` module defines the following constants:
324324

325325
.. data:: Py_DEBUG
326326

327-
True if Python is built with the :c:macro:`Py_DEBUG` macro defined: if
328-
Python is :ref:`built in debug mode <debug-build>`
329-
(:option:`./configure --with-pydebug <--with-pydebug>`).
327+
True if Python was built with the :c:macro:`Py_DEBUG` macro
328+
defined, that is, if
329+
Python was :ref:`built in debug mode <debug-build>`.
330330

331331
.. versionadded:: 3.12
332332

Doc/whatsnew/3.13.rst

+1-35
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,6 @@ Interpreter improvements:
9292
New Features
9393
============
9494

95-
* The cyclic garbage collector is now incremental.
96-
This means that maximum pause times are reduced,
97-
by an order of magnitude or more for larger heaps.
98-
9995
Improved Error Messages
10096
-----------------------
10197

@@ -105,13 +101,6 @@ Improved Error Messages
105101
variables. See also :ref:`using-on-controlling-color`.
106102
(Contributed by Pablo Galindo Salgado in :gh:`112730`.)
107103

108-
Incremental Garbage Collection
109-
------------------------------
110-
111-
* The cycle garbage collector is now incremental.
112-
This means that maximum pause times are reduced
113-
by an order of magnitude or more for larger heaps.
114-
115104
Other Language Changes
116105
======================
117106

@@ -257,29 +246,6 @@ fractions
257246
sign handling, minimum width and grouping. (Contributed by Mark Dickinson
258247
in :gh:`111320`.)
259248

260-
gc
261-
--
262-
* The cyclic garbage collector is now incremental, which changes the meanings
263-
of the results of :meth:`gc.get_threshold` and :meth:`gc.get_threshold` as
264-
well as :meth:`gc.get_count` and :meth:`gc.get_stats`.
265-
* :meth:`gc.get_threshold` returns a three-tuple for backwards compatibility,
266-
the first value is the threshold for young collections, as before, the second
267-
value determines the rate at which the old collection is scanned; the
268-
default is 10 and higher values mean that the old collection is scanned more slowly.
269-
The third value is meangless and is always zero.
270-
* :meth:`gc.set_threshold` ignores any items after the second.
271-
* :meth:`gc.get_count` and :meth:`gc.get_stats`.
272-
These functions return the same format of results as before.
273-
The only difference is that instead of the results refering to
274-
the young, aging and old generations, the results refer to the
275-
young generation and the aging and collecting spaces of the old generation.
276-
277-
In summary, code that attempted to manipulate the behavior of the cycle GC may
278-
not work as well as intended, but it is very unlikely to harmful.
279-
All other code will work just fine.
280-
Uses should avoid calling :meth:`gc.collect` unless their workload is episodic,
281-
but that has always been the case to some extent.
282-
283249
glob
284250
----
285251

@@ -391,7 +357,7 @@ pathlib
391357
(Contributed by Barney Gale in :gh:`89812`.)
392358

393359
* Add :meth:`pathlib.Path.from_uri`, a new constructor to create a :class:`pathlib.Path`
394-
object from a 'file' URI (``file:/``).
360+
object from a 'file' URI (``file://``).
395361
(Contributed by Barney Gale in :gh:`107465`.)
396362

397363
* Add :meth:`pathlib.PurePath.full_match` for matching paths with

Include/internal/pycore_critical_section.h

+46
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,37 @@ extern "C" {
104104
# define Py_END_CRITICAL_SECTION2() \
105105
_PyCriticalSection2_End(&_cs2); \
106106
}
107+
108+
// Asserts that the mutex is locked. The mutex must be held by the
109+
// top-most critical section otherwise there's the possibility
110+
// that the mutex would be swalled out in some code paths.
111+
#define _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(mutex) \
112+
_PyCriticalSection_AssertHeld(mutex)
113+
114+
// Asserts that the mutex for the given object is locked. The mutex must
115+
// be held by the top-most critical section otherwise there's the
116+
// possibility that the mutex would be swalled out in some code paths.
117+
#ifdef Py_DEBUG
118+
119+
#define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op) \
120+
if (Py_REFCNT(op) != 1) { \
121+
_Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&_PyObject_CAST(op)->ob_mutex); \
122+
}
123+
124+
#else /* Py_DEBUG */
125+
126+
#define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op)
127+
128+
#endif /* Py_DEBUG */
129+
107130
#else /* !Py_GIL_DISABLED */
108131
// The critical section APIs are no-ops with the GIL.
109132
# define Py_BEGIN_CRITICAL_SECTION(op)
110133
# define Py_END_CRITICAL_SECTION()
111134
# define Py_BEGIN_CRITICAL_SECTION2(a, b)
112135
# define Py_END_CRITICAL_SECTION2()
136+
# define _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(mutex)
137+
# define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op)
113138
#endif /* !Py_GIL_DISABLED */
114139

115140
typedef struct {
@@ -236,6 +261,27 @@ _PyCriticalSection2_End(_PyCriticalSection2 *c)
236261
PyAPI_FUNC(void)
237262
_PyCriticalSection_SuspendAll(PyThreadState *tstate);
238263

264+
#ifdef Py_GIL_DISABLED
265+
266+
static inline void
267+
_PyCriticalSection_AssertHeld(PyMutex *mutex) {
268+
#ifdef Py_DEBUG
269+
PyThreadState *tstate = _PyThreadState_GET();
270+
uintptr_t prev = tstate->critical_section;
271+
if (prev & _Py_CRITICAL_SECTION_TWO_MUTEXES) {
272+
_PyCriticalSection2 *cs = (_PyCriticalSection2 *)(prev & ~_Py_CRITICAL_SECTION_MASK);
273+
assert(cs != NULL && (cs->base.mutex == mutex || cs->mutex2 == mutex));
274+
}
275+
else {
276+
_PyCriticalSection *cs = (_PyCriticalSection *)(tstate->critical_section & ~_Py_CRITICAL_SECTION_MASK);
277+
assert(cs != NULL && cs->mutex == mutex);
278+
}
279+
280+
#endif
281+
}
282+
283+
#endif
284+
239285
#ifdef __cplusplus
240286
}
241287
#endif

Include/internal/pycore_gc.h

+15-27
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,11 @@ static inline void _PyObject_GC_SET_SHARED(PyObject *op) {
8888

8989
/* Bit flags for _gc_prev */
9090
/* Bit 0 is set when tp_finalize is called */
91-
#define _PyGC_PREV_MASK_FINALIZED 1
91+
#define _PyGC_PREV_MASK_FINALIZED (1)
9292
/* Bit 1 is set when the object is in generation which is GCed currently. */
93-
#define _PyGC_PREV_MASK_COLLECTING 2
94-
95-
/* Bit 0 is set if the object belongs to old space 1 */
96-
#define _PyGC_NEXT_MASK_OLD_SPACE_1 1
97-
93+
#define _PyGC_PREV_MASK_COLLECTING (2)
9894
/* The (N-2) most significant bits contain the real address. */
99-
#define _PyGC_PREV_SHIFT 2
95+
#define _PyGC_PREV_SHIFT (2)
10096
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
10197

10298
/* set for debugging information */
@@ -122,21 +118,18 @@ typedef enum {
122118
// Lowest bit of _gc_next is used for flags only in GC.
123119
// But it is always 0 for normal code.
124120
static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) {
125-
uintptr_t next = gc->_gc_next & _PyGC_PREV_MASK;
121+
uintptr_t next = gc->_gc_next;
126122
return (PyGC_Head*)next;
127123
}
128124
static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) {
129-
uintptr_t unext = (uintptr_t)next;
130-
assert((unext & ~_PyGC_PREV_MASK) == 0);
131-
gc->_gc_next = (gc->_gc_next & ~_PyGC_PREV_MASK) | unext;
125+
gc->_gc_next = (uintptr_t)next;
132126
}
133127

134128
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
135129
static inline PyGC_Head* _PyGCHead_PREV(PyGC_Head *gc) {
136130
uintptr_t prev = (gc->_gc_prev & _PyGC_PREV_MASK);
137131
return (PyGC_Head*)prev;
138132
}
139-
140133
static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) {
141134
uintptr_t uprev = (uintptr_t)prev;
142135
assert((uprev & ~_PyGC_PREV_MASK) == 0);
@@ -222,13 +215,6 @@ struct gc_generation {
222215
generations */
223216
};
224217

225-
struct gc_collection_stats {
226-
/* number of collected objects */
227-
Py_ssize_t collected;
228-
/* total number of uncollectable objects (put into gc.garbage) */
229-
Py_ssize_t uncollectable;
230-
};
231-
232218
/* Running stats per generation */
233219
struct gc_generation_stats {
234220
/* total number of collections */
@@ -250,8 +236,8 @@ struct _gc_runtime_state {
250236
int enabled;
251237
int debug;
252238
/* linked lists of container objects */
253-
struct gc_generation young;
254-
struct gc_generation old[2];
239+
struct gc_generation generations[NUM_GENERATIONS];
240+
PyGC_Head *generation0;
255241
/* a permanent generation which won't be collected */
256242
struct gc_generation permanent_generation;
257243
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
@@ -264,20 +250,22 @@ struct _gc_runtime_state {
264250
/* This is the number of objects that survived the last full
265251
collection. It approximates the number of long lived objects
266252
tracked by the GC.
253+
267254
(by "full collection", we mean a collection of the oldest
268255
generation). */
269256
Py_ssize_t long_lived_total;
270-
271-
Py_ssize_t work_to_do;
272-
/* Which of the old spaces is the visited space */
273-
int visited_space;
257+
/* This is the number of objects that survived all "non-full"
258+
collections, and are awaiting to undergo a full collection for
259+
the first time. */
260+
Py_ssize_t long_lived_pending;
274261
};
275262

276263

277264
extern void _PyGC_InitState(struct _gc_runtime_state *);
278265

279-
extern Py_ssize_t _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason);
280-
extern void _PyGC_CollectNoFail(PyThreadState *tstate);
266+
extern Py_ssize_t _PyGC_Collect(PyThreadState *tstate, int generation,
267+
_PyGC_Reason reason);
268+
extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate);
281269

282270
/* Freeze objects tracked by the GC and ignore them in future collections. */
283271
extern void _PyGC_Freeze(PyInterpreterState *interp);

Include/internal/pycore_object.h

+14-3
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,19 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
125125
}
126126
#define _Py_RefcntAdd(op, n) _Py_RefcntAdd(_PyObject_CAST(op), n)
127127

128-
extern void _Py_SetImmortal(PyObject *op);
128+
static inline void _Py_SetImmortal(PyObject *op)
129+
{
130+
if (op) {
131+
#ifdef Py_GIL_DISABLED
132+
op->ob_tid = _Py_UNOWNED_TID;
133+
op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL;
134+
op->ob_ref_shared = 0;
135+
#else
136+
op->ob_refcnt = _Py_IMMORTAL_REFCNT;
137+
#endif
138+
}
139+
}
140+
#define _Py_SetImmortal(op) _Py_SetImmortal(_PyObject_CAST(op))
129141

130142
// Makes an immortal object mortal again with the specified refcnt. Should only
131143
// be used during runtime finalization.
@@ -313,12 +325,11 @@ static inline void _PyObject_GC_TRACK(
313325
filename, lineno, __func__);
314326

315327
PyInterpreterState *interp = _PyInterpreterState_GET();
316-
PyGC_Head *generation0 = &interp->gc.young.head;
328+
PyGC_Head *generation0 = interp->gc.generation0;
317329
PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);
318330
_PyGCHead_SET_NEXT(last, gc);
319331
_PyGCHead_SET_PREV(gc, last);
320332
_PyGCHead_SET_NEXT(gc, generation0);
321-
assert((gc->_gc_next & _PyGC_NEXT_MASK_OLD_SPACE_1) == 0);
322333
generation0->_gc_prev = (uintptr_t)gc;
323334
#endif
324335
}

Include/internal/pycore_runtime_init.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ extern PyTypeObject _PyExc_MemoryError;
162162
}, \
163163
.gc = { \
164164
.enabled = 1, \
165-
.young = { .threshold = 2000, }, \
166-
.old = { \
165+
.generations = { \
166+
/* .head is set in _PyGC_InitState(). */ \
167+
{ .threshold = 700, }, \
168+
{ .threshold = 10, }, \
167169
{ .threshold = 10, }, \
168-
{ .threshold = 0, }, \
169170
}, \
170-
.work_to_do = -5000, \
171171
}, \
172172
.object_state = _py_object_state_INIT(INTERP), \
173173
.dtoa = _dtoa_state_INIT(&(INTERP)), \

Lib/test/test_gc.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,19 @@ def test_collect_generations(self):
383383
# each call to collect(N)
384384
x = []
385385
gc.collect(0)
386-
# x is now in the old gen
386+
# x is now in gen 1
387387
a, b, c = gc.get_count()
388-
# We don't check a since its exact values depends on
388+
gc.collect(1)
389+
# x is now in gen 2
390+
d, e, f = gc.get_count()
391+
gc.collect(2)
392+
# x is now in gen 3
393+
g, h, i = gc.get_count()
394+
# We don't check a, d, g since their exact values depends on
389395
# internal implementation details of the interpreter.
390396
self.assertEqual((b, c), (1, 0))
397+
self.assertEqual((e, f), (0, 1))
398+
self.assertEqual((h, i), (0, 0))
391399

392400
def test_trashcan(self):
393401
class Ouch:
@@ -838,6 +846,16 @@ def test_get_objects_generations(self):
838846
self.assertFalse(
839847
any(l is element for element in gc.get_objects(generation=2))
840848
)
849+
gc.collect(generation=1)
850+
self.assertFalse(
851+
any(l is element for element in gc.get_objects(generation=0))
852+
)
853+
self.assertFalse(
854+
any(l is element for element in gc.get_objects(generation=1))
855+
)
856+
self.assertTrue(
857+
any(l is element for element in gc.get_objects(generation=2))
858+
)
841859
gc.collect(generation=2)
842860
self.assertFalse(
843861
any(l is element for element in gc.get_objects(generation=0))

Lib/test/test_listcomps.py

+12
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ def method(self):
156156
self.assertEqual(C.y, [4, 4, 4, 4, 4])
157157
self.assertIs(C().method(), C)
158158

159+
def test_references_super(self):
160+
code = """
161+
res = [super for x in [1]]
162+
"""
163+
self._check_in_scopes(code, outputs={"res": [super]})
164+
165+
def test_references___class__(self):
166+
code = """
167+
res = [__class__ for x in [1]]
168+
"""
169+
self._check_in_scopes(code, raises=NameError)
170+
159171
def test_inner_cell_shadows_outer(self):
160172
code = """
161173
items = [(lambda: i) for i in range(5)]

0 commit comments

Comments
 (0)