Skip to content

Commit eca5362

Browse files
gh-94673: Clarify About Runtime State Related to Static Builtin Types (gh-117761)
Guido pointed out to me that some details about the per-interpreter state for the builtin types aren't especially clear. I'm addressing that by: * adding a comment explaining that state * adding some asserts to point out the relationship between each index and the interp/global runtime state
1 parent 30f0643 commit eca5362

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

Include/internal/pycore_typeobject.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,43 @@ struct types_state {
6868
unsigned int next_version_tag;
6969

7070
struct type_cache type_cache;
71+
72+
/* Every static builtin type is initialized for each interpreter
73+
during its own initialization, including for the main interpreter
74+
during global runtime initialization. This is done by calling
75+
_PyStaticType_InitBuiltin().
76+
77+
The first time a static builtin type is initialized, all the
78+
normal PyType_Ready() stuff happens. The only difference from
79+
normal is that there are three PyTypeObject fields holding
80+
objects which are stored here (on PyInterpreterState) rather
81+
than in the corresponding PyTypeObject fields. Those are:
82+
tp_dict (cls.__dict__), tp_subclasses (cls.__subclasses__),
83+
and tp_weaklist.
84+
85+
When a subinterpreter is initialized, each static builtin type
86+
is still initialized, but only the interpreter-specific portion,
87+
namely those three objects.
88+
89+
Those objects are stored in the PyInterpreterState.types.builtins
90+
array, at the index corresponding to each specific static builtin
91+
type. That index (a size_t value) is stored in the tp_subclasses
92+
field. For static builtin types, we re-purposed the now-unused
93+
tp_subclasses to avoid adding another field to PyTypeObject.
94+
In all other cases tp_subclasses holds a dict like before.
95+
(The field was previously defined as PyObject*, but is now void*
96+
to reflect its dual use.)
97+
98+
The index for each static builtin type isn't statically assigned.
99+
Instead it is calculated the first time a type is initialized
100+
(by the main interpreter). The index matches the order in which
101+
the type was initialized relative to the others. The actual
102+
value comes from the current value of num_builtins_initialized,
103+
as each type is initialized for the main interpreter.
104+
105+
num_builtins_initialized is incremented once for each static
106+
builtin type. Once initialization is over for a subinterpreter,
107+
the value will be the same as for all other interpreters. */
71108
size_t num_builtins_initialized;
72109
static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
73110
PyMutex mutex;

Objects/typeobject.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,14 @@ _PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self)
162162
static void
163163
static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self)
164164
{
165-
if (!static_builtin_index_is_set(self)) {
165+
if (_Py_IsMainInterpreter(interp)) {
166+
assert(!static_builtin_index_is_set(self));
166167
static_builtin_index_set(self, interp->types.num_builtins_initialized);
167168
}
169+
else {
170+
assert(static_builtin_index_get(self) ==
171+
interp->types.num_builtins_initialized);
172+
}
168173
static_builtin_state *state = static_builtin_state_get(interp, self);
169174

170175
/* It should only be called once for each builtin type. */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. 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