aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Modules/gcmodule.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committerDaniil Cherednik <dcherednik@ydb.tech>2024-02-14 14:26:16 +0000
commit31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch)
treec1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Modules/gcmodule.c
parentfe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff)
downloadydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Modules/gcmodule.c')
-rw-r--r--contrib/tools/python3/src/Modules/gcmodule.c162
1 files changed, 109 insertions, 53 deletions
diff --git a/contrib/tools/python3/src/Modules/gcmodule.c b/contrib/tools/python3/src/Modules/gcmodule.c
index ff0188da1d..b7cb30ab7e 100644
--- a/contrib/tools/python3/src/Modules/gcmodule.c
+++ b/contrib/tools/python3/src/Modules/gcmodule.c
@@ -420,8 +420,20 @@ validate_list(PyGC_Head *head, enum flagstates flags)
static void
update_refs(PyGC_Head *containers)
{
+ PyGC_Head *next;
PyGC_Head *gc = GC_NEXT(containers);
- for (; gc != containers; gc = GC_NEXT(gc)) {
+
+ while (gc != containers) {
+ next = GC_NEXT(gc);
+ /* Move any object that might have become immortal to the
+ * permanent generation as the reference count is not accurately
+ * reflecting the actual number of live references to this object
+ */
+ if (_Py_IsImmortal(FROM_GC(gc))) {
+ gc_list_move(gc, &get_gc_state()->permanent_generation.head);
+ gc = next;
+ continue;
+ }
gc_reset_refs(gc, Py_REFCNT(FROM_GC(gc)));
/* Python's cyclic gc should never see an incoming refcount
* of 0: if something decref'ed to 0, it should have been
@@ -442,6 +454,7 @@ update_refs(PyGC_Head *containers)
* check instead of an assert?
*/
_PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0);
+ gc = next;
}
}
@@ -796,9 +809,12 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
continue;
- /* It supports weakrefs. Does it have any? */
- wrlist = (PyWeakReference **)
- _PyObject_GET_WEAKREFS_LISTPTR(op);
+ /* It supports weakrefs. Does it have any?
+ *
+ * This is never triggered for static types so we can avoid the
+ * (slightly) more costly _PyObject_GET_WEAKREFS_LISTPTR().
+ */
+ wrlist = _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(op);
/* `op` may have some weakrefs. March over the list, clear
* all the weakrefs, and move the weakrefs with callbacks
@@ -1374,10 +1390,19 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase,
return;
}
}
+
+ PyObject *phase_obj = PyUnicode_FromString(phase);
+ if (phase_obj == NULL) {
+ Py_XDECREF(info);
+ PyErr_WriteUnraisable(NULL);
+ return;
+ }
+
+ PyObject *stack[] = {phase_obj, info};
for (Py_ssize_t i=0; i<PyList_GET_SIZE(gcstate->callbacks); i++) {
PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i);
Py_INCREF(cb); /* make sure cb doesn't go away */
- r = PyObject_CallFunction(cb, "sO", phase, info);
+ r = PyObject_Vectorcall(cb, stack, 2, NULL);
if (r == NULL) {
PyErr_WriteUnraisable(cb);
}
@@ -1386,6 +1411,7 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase,
}
Py_DECREF(cb);
}
+ Py_DECREF(phase_obj);
Py_XDECREF(info);
assert(!_PyErr_Occurred(tstate));
}
@@ -1869,8 +1895,7 @@ gc_is_tracked(PyObject *module, PyObject *obj)
result = Py_True;
else
result = Py_False;
- Py_INCREF(result);
- return result;
+ return Py_NewRef(result);
}
/*[clinic input]
@@ -2021,6 +2046,7 @@ gcmodule_exec(PyObject *module)
static PyModuleDef_Slot gcmodule_slots[] = {
{Py_mod_exec, gcmodule_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL}
};
@@ -2082,11 +2108,10 @@ PyGC_Collect(void)
n = 0;
}
else {
- PyObject *exc, *value, *tb;
gcstate->collecting = 1;
- _PyErr_Fetch(tstate, &exc, &value, &tb);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1);
- _PyErr_Restore(tstate, exc, value, tb);
+ _PyErr_SetRaisedException(tstate, exc);
gcstate->collecting = 0;
}
@@ -2152,23 +2177,6 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
}
-static void
-gc_fini_untrack(PyGC_Head *list)
-{
- PyGC_Head *gc;
- for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) {
- PyObject *op = FROM_GC(gc);
- _PyObject_GC_UNTRACK(op);
- // gh-92036: If a deallocator function expect the object to be tracked
- // by the GC (ex: func_dealloc()), it can crash if called on an object
- // which is no longer tracked by the GC. Leak one strong reference on
- // purpose so the object is never deleted and its deallocator is not
- // called.
- Py_INCREF(op);
- }
-}
-
-
void
_PyGC_Fini(PyInterpreterState *interp)
{
@@ -2176,17 +2184,9 @@ _PyGC_Fini(PyInterpreterState *interp)
Py_CLEAR(gcstate->garbage);
Py_CLEAR(gcstate->callbacks);
- if (!_Py_IsMainInterpreter(interp)) {
- // bpo-46070: Explicitly untrack all objects currently tracked by the
- // GC. Otherwise, if an object is used later by another interpreter,
- // calling PyObject_GC_UnTrack() on the object crashs if the previous
- // or the next object of the PyGC_Head structure became a dangling
- // pointer.
- for (int i = 0; i < NUM_GENERATIONS; i++) {
- PyGC_Head *gen = GEN_HEAD(gcstate, i);
- gc_fini_untrack(gen);
- }
- }
+ /* We expect that none of this interpreters objects are shared
+ with other interpreters.
+ See https://github.com/python/cpython/issues/90228. */
}
/* for debugging */
@@ -2252,6 +2252,20 @@ PyObject_IS_GC(PyObject *obj)
}
void
+_Py_ScheduleGC(PyInterpreterState *interp)
+{
+ GCState *gcstate = &interp->gc;
+ if (gcstate->collecting == 1) {
+ return;
+ }
+ struct _ceval_state *ceval = &interp->ceval;
+ if (!_Py_atomic_load_relaxed(&ceval->gc_scheduled)) {
+ _Py_atomic_store_relaxed(&ceval->gc_scheduled, 1);
+ _Py_atomic_store_relaxed(&ceval->eval_breaker, 1);
+ }
+}
+
+void
_PyObject_GC_Link(PyObject *op)
{
PyGC_Head *g = AS_GC(op);
@@ -2268,12 +2282,19 @@ _PyObject_GC_Link(PyObject *op)
!gcstate->collecting &&
!_PyErr_Occurred(tstate))
{
- gcstate->collecting = 1;
- gc_collect_generations(tstate);
- gcstate->collecting = 0;
+ _Py_ScheduleGC(tstate->interp);
}
}
+void
+_Py_RunGC(PyThreadState *tstate)
+{
+ GCState *gcstate = &tstate->interp->gc;
+ gcstate->collecting = 1;
+ gc_collect_generations(tstate);
+ gcstate->collecting = 0;
+}
+
static PyObject *
gc_alloc(size_t basicsize, size_t presize)
{
@@ -2308,7 +2329,6 @@ _PyObject_GC_New(PyTypeObject *tp)
PyVarObject *
_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
{
- size_t size;
PyVarObject *op;
if (nitems < 0) {
@@ -2316,7 +2336,7 @@ _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
return NULL;
}
size_t presize = _PyType_PreHeaderSize(tp);
- size = _PyObject_VAR_SIZE(tp, nitems);
+ size_t size = _PyObject_VAR_SIZE(tp, nitems);
op = (PyVarObject *)gc_alloc(size, presize);
if (op == NULL) {
return NULL;
@@ -2325,20 +2345,34 @@ _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
return op;
}
+PyObject *
+PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *tp, size_t extra_size)
+{
+ size_t presize = _PyType_PreHeaderSize(tp);
+ PyObject *op = gc_alloc(_PyObject_SIZE(tp) + extra_size, presize);
+ if (op == NULL) {
+ return NULL;
+ }
+ memset(op, 0, _PyObject_SIZE(tp) + extra_size);
+ _PyObject_Init(op, tp);
+ return op;
+}
+
PyVarObject *
_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
{
const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
+ const size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type);
_PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op));
- if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
+ if (basicsize > (size_t)PY_SSIZE_T_MAX - presize) {
return (PyVarObject *)PyErr_NoMemory();
}
-
- PyGC_Head *g = AS_GC(op);
- g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize);
- if (g == NULL)
+ char *mem = (char *)op - presize;
+ mem = (char *)PyObject_Realloc(mem, presize + basicsize);
+ if (mem == NULL) {
return (PyVarObject *)PyErr_NoMemory();
- op = (PyVarObject *) FROM_GC(g);
+ }
+ op = (PyVarObject *) (mem + presize);
Py_SET_SIZE(op, nitems);
return op;
}
@@ -2351,15 +2385,13 @@ PyObject_GC_Del(void *op)
if (_PyObject_GC_IS_TRACKED(op)) {
gc_list_remove(g);
#ifdef Py_DEBUG
- PyObject *exc, *exc_value, *exc_tb;
- PyErr_Fetch(&exc, &exc_value, &exc_tb);
+ PyObject *exc = PyErr_GetRaisedException();
if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
"gc", NULL, "Object of type %s is not untracked before destruction",
((PyObject*)op)->ob_type->tp_name)) {
PyErr_WriteUnraisable(NULL);
}
- if (exc != NULL)
- PyErr_Restore(exc, exc_value, exc_tb);
+ PyErr_SetRaisedException(exc);
#endif
}
GCState *gcstate = get_gc_state();
@@ -2386,3 +2418,27 @@ PyObject_GC_IsFinalized(PyObject *obj)
}
return 0;
}
+
+void
+PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
+{
+ size_t i;
+ GCState *gcstate = get_gc_state();
+ int origenstate = gcstate->enabled;
+ gcstate->enabled = 0;
+ for (i = 0; i < NUM_GENERATIONS; i++) {
+ PyGC_Head *gc_list, *gc;
+ gc_list = GEN_HEAD(gcstate, i);
+ for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) {
+ PyObject *op = FROM_GC(gc);
+ Py_INCREF(op);
+ int res = callback(op, arg);
+ Py_DECREF(op);
+ if (!res) {
+ goto done;
+ }
+ }
+ }
+done:
+ gcstate->enabled = origenstate;
+}