Skip to content

Commit 1d1393a

Browse files
Add _Py_EnsureImmortal() and _Py_ImmortalObjectsFini().
1 parent 018ee57 commit 1d1393a

File tree

5 files changed

+100
-9
lines changed

5 files changed

+100
-9
lines changed

Include/internal/pycore_global_objects.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ extern "C" {
2020
#define _PY_NSMALLNEGINTS 5
2121

2222

23+
struct _Py_immortalized_object {
24+
PyObject *obj;
25+
int final_refcnt;
26+
struct _Py_immortalized_object *next;
27+
};
28+
29+
struct _Py_immortalized_objects {
30+
Py_ssize_t count;
31+
struct _Py_immortalized_object *head;
32+
struct _Py_immortalized_object *last;
33+
#define _Py_IMMORTALIZED_ARRAY_SIZE 100
34+
struct _Py_immortalized_object _objects[_Py_IMMORTALIZED_ARRAY_SIZE];
35+
};
36+
37+
extern void _Py_EnsureImmortal(PyObject *);
38+
extern void _Py_ImmortalObjectsFini(void);
39+
40+
2341
// Only immutable objects should be considered runtime-global.
2442
// All others must be per-interpreter.
2543

Include/internal/pycore_runtime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ typedef struct pyruntimestate {
152152
struct _Py_unicode_runtime_state unicode_state;
153153
struct _types_runtime_state types;
154154

155+
/* All non-static immortal objects (need to be cleaned up during fini). */
156+
struct _Py_immortalized_objects immortalized_objects;
155157
/* All the objects that are shared by the runtime's interpreters. */
156158
struct _Py_static_objects static_objects;
157159

Objects/typeobject.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7055,15 +7055,9 @@ _PyStaticType_InitBuiltin(PyTypeObject *self)
70557055
static_builtin_state_clear(self);
70567056
}
70577057

7058-
_Py_SetImmortal(self->tp_dict);
7059-
if (!_Py_IsImmortal(self->tp_bases)) {
7060-
assert(PyTuple_GET_SIZE(self->tp_bases) > 0);
7061-
_Py_SetImmortal(self->tp_bases);
7062-
}
7063-
if (!_Py_IsImmortal(self->tp_mro)) {
7064-
assert(PyTuple_GET_SIZE(self->tp_mro) > 0);
7065-
_Py_SetImmortal(self->tp_mro);
7066-
}
7058+
_Py_EnsureImmortal(self->tp_dict);
7059+
_Py_EnsureImmortal(self->tp_bases);
7060+
_Py_EnsureImmortal(self->tp_mro);
70677061

70687062
return res;
70697063
}

Python/pylifecycle.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,7 @@ finalize_interp_clear(PyThreadState *tstate)
17331733
_Py_ClearFileSystemEncoding();
17341734
_Py_Deepfreeze_Fini();
17351735
_PyPerfTrampoline_Fini();
1736+
_Py_ImmortalObjectsFini();
17361737
}
17371738

17381739
finalize_interp_types(tstate->interp);

Python/pystate.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2758,6 +2758,82 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
27582758
}
27592759

27602760

2761+
/******************/
2762+
/* global objects */
2763+
/******************/
2764+
2765+
static void
2766+
immortalized_add(struct _Py_immortalized_objects *state, PyObject *obj)
2767+
{
2768+
struct _Py_immortalized_object *entry;
2769+
if (state->count < _Py_IMMORTALIZED_ARRAY_SIZE) {
2770+
entry = &state->_objects[state->count];
2771+
}
2772+
else {
2773+
entry = PyMem_RawMalloc(sizeof(*entry));
2774+
if (entry == NULL) {
2775+
Py_FatalError("could not allocate immortalized list entry");
2776+
}
2777+
}
2778+
2779+
entry->obj = obj;
2780+
entry->final_refcnt = Py_REFCNT(obj);
2781+
entry->next = NULL;
2782+
2783+
if (state->head == NULL) {
2784+
assert(state->count == 0);
2785+
assert(state->last == NULL);
2786+
state->head = entry;
2787+
}
2788+
else {
2789+
state->last->next = entry;
2790+
}
2791+
state->count += 1;
2792+
state->last = entry;
2793+
}
2794+
2795+
static void
2796+
immortalized_fini(struct _Py_immortalized_objects *state)
2797+
{
2798+
struct _Py_immortalized_object *next = state->head;
2799+
state->head = NULL;
2800+
state->last = NULL;
2801+
for (int i = 0; i < _Py_IMMORTALIZED_ARRAY_SIZE && next != NULL; i++) {
2802+
struct _Py_immortalized_object *entry = next;
2803+
next = entry->next;
2804+
entry->obj->ob_refcnt = entry->final_refcnt;
2805+
}
2806+
while (next != NULL) {
2807+
struct _Py_immortalized_object *entry = next;
2808+
next = next->next;
2809+
entry->obj->ob_refcnt = entry->final_refcnt;
2810+
PyMem_RawFree(entry);
2811+
}
2812+
}
2813+
2814+
void
2815+
_Py_EnsureImmortal(PyObject *obj)
2816+
{
2817+
assert(_Py_IsMainInterpreter(_PyInterpreterState_GET()));
2818+
if (_Py_IsImmortal(obj)) {
2819+
return;
2820+
}
2821+
2822+
_Py_SetImmortal(obj);
2823+
immortalized_add(&_PyRuntime.immortalized_objects, obj);
2824+
}
2825+
2826+
void
2827+
_Py_ImmortalObjectsFini(void)
2828+
{
2829+
immortalized_fini(&_PyRuntime.immortalized_objects);
2830+
}
2831+
2832+
2833+
/*************/
2834+
/* other API */
2835+
/*************/
2836+
27612837
_PyFrameEvalFunction
27622838
_PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)
27632839
{

0 commit comments

Comments
 (0)