17db96d56Sopenharmony_ci/* 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci Reference Cycle Garbage Collection 47db96d56Sopenharmony_ci ================================== 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ci Neil Schemenauer <nas@arctrix.com> 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ci Based on a post on the python-dev list. Ideas from Guido van Rossum, 97db96d56Sopenharmony_ci Eric Tiedemann, and various others. 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci http://www.arctrix.com/nas/python/gc/ 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ci The following mailing list threads provide a historical perspective on 147db96d56Sopenharmony_ci the design of this module. Note that a fair amount of refinement has 157db96d56Sopenharmony_ci occurred since those discussions. 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci http://mail.python.org/pipermail/python-dev/2000-March/002385.html 187db96d56Sopenharmony_ci http://mail.python.org/pipermail/python-dev/2000-March/002434.html 197db96d56Sopenharmony_ci http://mail.python.org/pipermail/python-dev/2000-March/002497.html 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci For a highlevel view of the collection process, read the collect 227db96d56Sopenharmony_ci function. 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci*/ 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci#include "Python.h" 277db96d56Sopenharmony_ci#include "pycore_context.h" 287db96d56Sopenharmony_ci#include "pycore_initconfig.h" 297db96d56Sopenharmony_ci#include "pycore_interp.h" // PyInterpreterState.gc 307db96d56Sopenharmony_ci#include "pycore_object.h" 317db96d56Sopenharmony_ci#include "pycore_pyerrors.h" 327db96d56Sopenharmony_ci#include "pycore_pystate.h" // _PyThreadState_GET() 337db96d56Sopenharmony_ci#include "pydtrace.h" 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_citypedef struct _gc_runtime_state GCState; 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci/*[clinic input] 387db96d56Sopenharmony_cimodule gc 397db96d56Sopenharmony_ci[clinic start generated code]*/ 407db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5c9690ecc842d79]*/ 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci#ifdef Py_DEBUG 447db96d56Sopenharmony_ci# define GC_DEBUG 457db96d56Sopenharmony_ci#endif 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci#define GC_NEXT _PyGCHead_NEXT 487db96d56Sopenharmony_ci#define GC_PREV _PyGCHead_PREV 497db96d56Sopenharmony_ci 507db96d56Sopenharmony_ci// update_refs() set this bit for all objects in current generation. 517db96d56Sopenharmony_ci// subtract_refs() and move_unreachable() uses this to distinguish 527db96d56Sopenharmony_ci// visited object is in GCing or not. 537db96d56Sopenharmony_ci// 547db96d56Sopenharmony_ci// move_unreachable() removes this flag from reachable objects. 557db96d56Sopenharmony_ci// Only unreachable objects have this flag. 567db96d56Sopenharmony_ci// 577db96d56Sopenharmony_ci// No objects in interpreter have this flag after GC ends. 587db96d56Sopenharmony_ci#define PREV_MASK_COLLECTING _PyGC_PREV_MASK_COLLECTING 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci// Lowest bit of _gc_next is used for UNREACHABLE flag. 617db96d56Sopenharmony_ci// 627db96d56Sopenharmony_ci// This flag represents the object is in unreachable list in move_unreachable() 637db96d56Sopenharmony_ci// 647db96d56Sopenharmony_ci// Although this flag is used only in move_unreachable(), move_unreachable() 657db96d56Sopenharmony_ci// doesn't clear this flag to skip unnecessary iteration. 667db96d56Sopenharmony_ci// move_legacy_finalizers() removes this flag instead. 677db96d56Sopenharmony_ci// Between them, unreachable list is not normal list and we can not use 687db96d56Sopenharmony_ci// most gc_list_* functions for it. 697db96d56Sopenharmony_ci#define NEXT_MASK_UNREACHABLE (1) 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci/* Get an object's GC head */ 727db96d56Sopenharmony_ci#define AS_GC(o) ((PyGC_Head *)(((char *)(o))-sizeof(PyGC_Head))) 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci/* Get the object given the GC head */ 757db96d56Sopenharmony_ci#define FROM_GC(g) ((PyObject *)(((char *)(g))+sizeof(PyGC_Head))) 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_cistatic inline int 787db96d56Sopenharmony_cigc_is_collecting(PyGC_Head *g) 797db96d56Sopenharmony_ci{ 807db96d56Sopenharmony_ci return (g->_gc_prev & PREV_MASK_COLLECTING) != 0; 817db96d56Sopenharmony_ci} 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_cistatic inline void 847db96d56Sopenharmony_cigc_clear_collecting(PyGC_Head *g) 857db96d56Sopenharmony_ci{ 867db96d56Sopenharmony_ci g->_gc_prev &= ~PREV_MASK_COLLECTING; 877db96d56Sopenharmony_ci} 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_cistatic inline Py_ssize_t 907db96d56Sopenharmony_cigc_get_refs(PyGC_Head *g) 917db96d56Sopenharmony_ci{ 927db96d56Sopenharmony_ci return (Py_ssize_t)(g->_gc_prev >> _PyGC_PREV_SHIFT); 937db96d56Sopenharmony_ci} 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_cistatic inline void 967db96d56Sopenharmony_cigc_set_refs(PyGC_Head *g, Py_ssize_t refs) 977db96d56Sopenharmony_ci{ 987db96d56Sopenharmony_ci g->_gc_prev = (g->_gc_prev & ~_PyGC_PREV_MASK) 997db96d56Sopenharmony_ci | ((uintptr_t)(refs) << _PyGC_PREV_SHIFT); 1007db96d56Sopenharmony_ci} 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_cistatic inline void 1037db96d56Sopenharmony_cigc_reset_refs(PyGC_Head *g, Py_ssize_t refs) 1047db96d56Sopenharmony_ci{ 1057db96d56Sopenharmony_ci g->_gc_prev = (g->_gc_prev & _PyGC_PREV_MASK_FINALIZED) 1067db96d56Sopenharmony_ci | PREV_MASK_COLLECTING 1077db96d56Sopenharmony_ci | ((uintptr_t)(refs) << _PyGC_PREV_SHIFT); 1087db96d56Sopenharmony_ci} 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_cistatic inline void 1117db96d56Sopenharmony_cigc_decref(PyGC_Head *g) 1127db96d56Sopenharmony_ci{ 1137db96d56Sopenharmony_ci _PyObject_ASSERT_WITH_MSG(FROM_GC(g), 1147db96d56Sopenharmony_ci gc_get_refs(g) > 0, 1157db96d56Sopenharmony_ci "refcount is too small"); 1167db96d56Sopenharmony_ci g->_gc_prev -= 1 << _PyGC_PREV_SHIFT; 1177db96d56Sopenharmony_ci} 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ci/* set for debugging information */ 1207db96d56Sopenharmony_ci#define DEBUG_STATS (1<<0) /* print collection statistics */ 1217db96d56Sopenharmony_ci#define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ 1227db96d56Sopenharmony_ci#define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */ 1237db96d56Sopenharmony_ci#define DEBUG_SAVEALL (1<<5) /* save all garbage in gc.garbage */ 1247db96d56Sopenharmony_ci#define DEBUG_LEAK DEBUG_COLLECTABLE | \ 1257db96d56Sopenharmony_ci DEBUG_UNCOLLECTABLE | \ 1267db96d56Sopenharmony_ci DEBUG_SAVEALL 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci#define GEN_HEAD(gcstate, n) (&(gcstate)->generations[n].head) 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_cistatic GCState * 1327db96d56Sopenharmony_ciget_gc_state(void) 1337db96d56Sopenharmony_ci{ 1347db96d56Sopenharmony_ci PyInterpreterState *interp = _PyInterpreterState_GET(); 1357db96d56Sopenharmony_ci return &interp->gc; 1367db96d56Sopenharmony_ci} 1377db96d56Sopenharmony_ci 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_civoid 1407db96d56Sopenharmony_ci_PyGC_InitState(GCState *gcstate) 1417db96d56Sopenharmony_ci{ 1427db96d56Sopenharmony_ci#define INIT_HEAD(GEN) \ 1437db96d56Sopenharmony_ci do { \ 1447db96d56Sopenharmony_ci GEN.head._gc_next = (uintptr_t)&GEN.head; \ 1457db96d56Sopenharmony_ci GEN.head._gc_prev = (uintptr_t)&GEN.head; \ 1467db96d56Sopenharmony_ci } while (0) 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ci for (int i = 0; i < NUM_GENERATIONS; i++) { 1497db96d56Sopenharmony_ci assert(gcstate->generations[i].count == 0); 1507db96d56Sopenharmony_ci INIT_HEAD(gcstate->generations[i]); 1517db96d56Sopenharmony_ci }; 1527db96d56Sopenharmony_ci gcstate->generation0 = GEN_HEAD(gcstate, 0); 1537db96d56Sopenharmony_ci INIT_HEAD(gcstate->permanent_generation); 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci#undef INIT_HEAD 1567db96d56Sopenharmony_ci} 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ciPyStatus 1607db96d56Sopenharmony_ci_PyGC_Init(PyInterpreterState *interp) 1617db96d56Sopenharmony_ci{ 1627db96d56Sopenharmony_ci GCState *gcstate = &interp->gc; 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci gcstate->garbage = PyList_New(0); 1657db96d56Sopenharmony_ci if (gcstate->garbage == NULL) { 1667db96d56Sopenharmony_ci return _PyStatus_NO_MEMORY(); 1677db96d56Sopenharmony_ci } 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci gcstate->callbacks = PyList_New(0); 1707db96d56Sopenharmony_ci if (gcstate->callbacks == NULL) { 1717db96d56Sopenharmony_ci return _PyStatus_NO_MEMORY(); 1727db96d56Sopenharmony_ci } 1737db96d56Sopenharmony_ci 1747db96d56Sopenharmony_ci return _PyStatus_OK(); 1757db96d56Sopenharmony_ci} 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci/* 1797db96d56Sopenharmony_ci_gc_prev values 1807db96d56Sopenharmony_ci--------------- 1817db96d56Sopenharmony_ci 1827db96d56Sopenharmony_ciBetween collections, _gc_prev is used for doubly linked list. 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ciLowest two bits of _gc_prev are used for flags. 1857db96d56Sopenharmony_ciPREV_MASK_COLLECTING is used only while collecting and cleared before GC ends 1867db96d56Sopenharmony_cior _PyObject_GC_UNTRACK() is called. 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ciDuring a collection, _gc_prev is temporary used for gc_refs, and the gc list 1897db96d56Sopenharmony_ciis singly linked until _gc_prev is restored. 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_cigc_refs 1927db96d56Sopenharmony_ci At the start of a collection, update_refs() copies the true refcount 1937db96d56Sopenharmony_ci to gc_refs, for each object in the generation being collected. 1947db96d56Sopenharmony_ci subtract_refs() then adjusts gc_refs so that it equals the number of 1957db96d56Sopenharmony_ci times an object is referenced directly from outside the generation 1967db96d56Sopenharmony_ci being collected. 1977db96d56Sopenharmony_ci 1987db96d56Sopenharmony_ciPREV_MASK_COLLECTING 1997db96d56Sopenharmony_ci Objects in generation being collected are marked PREV_MASK_COLLECTING in 2007db96d56Sopenharmony_ci update_refs(). 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci_gc_next values 2047db96d56Sopenharmony_ci--------------- 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci_gc_next takes these values: 2077db96d56Sopenharmony_ci 2087db96d56Sopenharmony_ci0 2097db96d56Sopenharmony_ci The object is not tracked 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci!= 0 2127db96d56Sopenharmony_ci Pointer to the next object in the GC list. 2137db96d56Sopenharmony_ci Additionally, lowest bit is used temporary for 2147db96d56Sopenharmony_ci NEXT_MASK_UNREACHABLE flag described below. 2157db96d56Sopenharmony_ci 2167db96d56Sopenharmony_ciNEXT_MASK_UNREACHABLE 2177db96d56Sopenharmony_ci move_unreachable() then moves objects not reachable (whether directly or 2187db96d56Sopenharmony_ci indirectly) from outside the generation into an "unreachable" set and 2197db96d56Sopenharmony_ci set this flag. 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci Objects that are found to be reachable have gc_refs set to 1. 2227db96d56Sopenharmony_ci When this flag is set for the reachable object, the object must be in 2237db96d56Sopenharmony_ci "unreachable" set. 2247db96d56Sopenharmony_ci The flag is unset and the object is moved back to "reachable" set. 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci move_legacy_finalizers() will remove this flag from "unreachable" set. 2277db96d56Sopenharmony_ci*/ 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci/*** list functions ***/ 2307db96d56Sopenharmony_ci 2317db96d56Sopenharmony_cistatic inline void 2327db96d56Sopenharmony_cigc_list_init(PyGC_Head *list) 2337db96d56Sopenharmony_ci{ 2347db96d56Sopenharmony_ci // List header must not have flags. 2357db96d56Sopenharmony_ci // We can assign pointer by simple cast. 2367db96d56Sopenharmony_ci list->_gc_prev = (uintptr_t)list; 2377db96d56Sopenharmony_ci list->_gc_next = (uintptr_t)list; 2387db96d56Sopenharmony_ci} 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_cistatic inline int 2417db96d56Sopenharmony_cigc_list_is_empty(PyGC_Head *list) 2427db96d56Sopenharmony_ci{ 2437db96d56Sopenharmony_ci return (list->_gc_next == (uintptr_t)list); 2447db96d56Sopenharmony_ci} 2457db96d56Sopenharmony_ci 2467db96d56Sopenharmony_ci/* Append `node` to `list`. */ 2477db96d56Sopenharmony_cistatic inline void 2487db96d56Sopenharmony_cigc_list_append(PyGC_Head *node, PyGC_Head *list) 2497db96d56Sopenharmony_ci{ 2507db96d56Sopenharmony_ci PyGC_Head *last = (PyGC_Head *)list->_gc_prev; 2517db96d56Sopenharmony_ci 2527db96d56Sopenharmony_ci // last <-> node 2537db96d56Sopenharmony_ci _PyGCHead_SET_PREV(node, last); 2547db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(last, node); 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci // node <-> list 2577db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(node, list); 2587db96d56Sopenharmony_ci list->_gc_prev = (uintptr_t)node; 2597db96d56Sopenharmony_ci} 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci/* Remove `node` from the gc list it's currently in. */ 2627db96d56Sopenharmony_cistatic inline void 2637db96d56Sopenharmony_cigc_list_remove(PyGC_Head *node) 2647db96d56Sopenharmony_ci{ 2657db96d56Sopenharmony_ci PyGC_Head *prev = GC_PREV(node); 2667db96d56Sopenharmony_ci PyGC_Head *next = GC_NEXT(node); 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(prev, next); 2697db96d56Sopenharmony_ci _PyGCHead_SET_PREV(next, prev); 2707db96d56Sopenharmony_ci 2717db96d56Sopenharmony_ci node->_gc_next = 0; /* object is not currently tracked */ 2727db96d56Sopenharmony_ci} 2737db96d56Sopenharmony_ci 2747db96d56Sopenharmony_ci/* Move `node` from the gc list it's currently in (which is not explicitly 2757db96d56Sopenharmony_ci * named here) to the end of `list`. This is semantically the same as 2767db96d56Sopenharmony_ci * gc_list_remove(node) followed by gc_list_append(node, list). 2777db96d56Sopenharmony_ci */ 2787db96d56Sopenharmony_cistatic void 2797db96d56Sopenharmony_cigc_list_move(PyGC_Head *node, PyGC_Head *list) 2807db96d56Sopenharmony_ci{ 2817db96d56Sopenharmony_ci /* Unlink from current list. */ 2827db96d56Sopenharmony_ci PyGC_Head *from_prev = GC_PREV(node); 2837db96d56Sopenharmony_ci PyGC_Head *from_next = GC_NEXT(node); 2847db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(from_prev, from_next); 2857db96d56Sopenharmony_ci _PyGCHead_SET_PREV(from_next, from_prev); 2867db96d56Sopenharmony_ci 2877db96d56Sopenharmony_ci /* Relink at end of new list. */ 2887db96d56Sopenharmony_ci // list must not have flags. So we can skip macros. 2897db96d56Sopenharmony_ci PyGC_Head *to_prev = (PyGC_Head*)list->_gc_prev; 2907db96d56Sopenharmony_ci _PyGCHead_SET_PREV(node, to_prev); 2917db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(to_prev, node); 2927db96d56Sopenharmony_ci list->_gc_prev = (uintptr_t)node; 2937db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(node, list); 2947db96d56Sopenharmony_ci} 2957db96d56Sopenharmony_ci 2967db96d56Sopenharmony_ci/* append list `from` onto list `to`; `from` becomes an empty list */ 2977db96d56Sopenharmony_cistatic void 2987db96d56Sopenharmony_cigc_list_merge(PyGC_Head *from, PyGC_Head *to) 2997db96d56Sopenharmony_ci{ 3007db96d56Sopenharmony_ci assert(from != to); 3017db96d56Sopenharmony_ci if (!gc_list_is_empty(from)) { 3027db96d56Sopenharmony_ci PyGC_Head *to_tail = GC_PREV(to); 3037db96d56Sopenharmony_ci PyGC_Head *from_head = GC_NEXT(from); 3047db96d56Sopenharmony_ci PyGC_Head *from_tail = GC_PREV(from); 3057db96d56Sopenharmony_ci assert(from_head != from); 3067db96d56Sopenharmony_ci assert(from_tail != from); 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(to_tail, from_head); 3097db96d56Sopenharmony_ci _PyGCHead_SET_PREV(from_head, to_tail); 3107db96d56Sopenharmony_ci 3117db96d56Sopenharmony_ci _PyGCHead_SET_NEXT(from_tail, to); 3127db96d56Sopenharmony_ci _PyGCHead_SET_PREV(to, from_tail); 3137db96d56Sopenharmony_ci } 3147db96d56Sopenharmony_ci gc_list_init(from); 3157db96d56Sopenharmony_ci} 3167db96d56Sopenharmony_ci 3177db96d56Sopenharmony_cistatic Py_ssize_t 3187db96d56Sopenharmony_cigc_list_size(PyGC_Head *list) 3197db96d56Sopenharmony_ci{ 3207db96d56Sopenharmony_ci PyGC_Head *gc; 3217db96d56Sopenharmony_ci Py_ssize_t n = 0; 3227db96d56Sopenharmony_ci for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) { 3237db96d56Sopenharmony_ci n++; 3247db96d56Sopenharmony_ci } 3257db96d56Sopenharmony_ci return n; 3267db96d56Sopenharmony_ci} 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci/* Walk the list and mark all objects as non-collecting */ 3297db96d56Sopenharmony_cistatic inline void 3307db96d56Sopenharmony_cigc_list_clear_collecting(PyGC_Head *collectable) 3317db96d56Sopenharmony_ci{ 3327db96d56Sopenharmony_ci PyGC_Head *gc; 3337db96d56Sopenharmony_ci for (gc = GC_NEXT(collectable); gc != collectable; gc = GC_NEXT(gc)) { 3347db96d56Sopenharmony_ci gc_clear_collecting(gc); 3357db96d56Sopenharmony_ci } 3367db96d56Sopenharmony_ci} 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_ci/* Append objects in a GC list to a Python list. 3397db96d56Sopenharmony_ci * Return 0 if all OK, < 0 if error (out of memory for list) 3407db96d56Sopenharmony_ci */ 3417db96d56Sopenharmony_cistatic int 3427db96d56Sopenharmony_ciappend_objects(PyObject *py_list, PyGC_Head *gc_list) 3437db96d56Sopenharmony_ci{ 3447db96d56Sopenharmony_ci PyGC_Head *gc; 3457db96d56Sopenharmony_ci for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { 3467db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 3477db96d56Sopenharmony_ci if (op != py_list) { 3487db96d56Sopenharmony_ci if (PyList_Append(py_list, op)) { 3497db96d56Sopenharmony_ci return -1; /* exception */ 3507db96d56Sopenharmony_ci } 3517db96d56Sopenharmony_ci } 3527db96d56Sopenharmony_ci } 3537db96d56Sopenharmony_ci return 0; 3547db96d56Sopenharmony_ci} 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci// Constants for validate_list's flags argument. 3577db96d56Sopenharmony_cienum flagstates {collecting_clear_unreachable_clear, 3587db96d56Sopenharmony_ci collecting_clear_unreachable_set, 3597db96d56Sopenharmony_ci collecting_set_unreachable_clear, 3607db96d56Sopenharmony_ci collecting_set_unreachable_set}; 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci#ifdef GC_DEBUG 3637db96d56Sopenharmony_ci// validate_list checks list consistency. And it works as document 3647db96d56Sopenharmony_ci// describing when flags are expected to be set / unset. 3657db96d56Sopenharmony_ci// `head` must be a doubly-linked gc list, although it's fine (expected!) if 3667db96d56Sopenharmony_ci// the prev and next pointers are "polluted" with flags. 3677db96d56Sopenharmony_ci// What's checked: 3687db96d56Sopenharmony_ci// - The `head` pointers are not polluted. 3697db96d56Sopenharmony_ci// - The objects' PREV_MASK_COLLECTING and NEXT_MASK_UNREACHABLE flags are all 3707db96d56Sopenharmony_ci// `set or clear, as specified by the 'flags' argument. 3717db96d56Sopenharmony_ci// - The prev and next pointers are mutually consistent. 3727db96d56Sopenharmony_cistatic void 3737db96d56Sopenharmony_civalidate_list(PyGC_Head *head, enum flagstates flags) 3747db96d56Sopenharmony_ci{ 3757db96d56Sopenharmony_ci assert((head->_gc_prev & PREV_MASK_COLLECTING) == 0); 3767db96d56Sopenharmony_ci assert((head->_gc_next & NEXT_MASK_UNREACHABLE) == 0); 3777db96d56Sopenharmony_ci uintptr_t prev_value = 0, next_value = 0; 3787db96d56Sopenharmony_ci switch (flags) { 3797db96d56Sopenharmony_ci case collecting_clear_unreachable_clear: 3807db96d56Sopenharmony_ci break; 3817db96d56Sopenharmony_ci case collecting_set_unreachable_clear: 3827db96d56Sopenharmony_ci prev_value = PREV_MASK_COLLECTING; 3837db96d56Sopenharmony_ci break; 3847db96d56Sopenharmony_ci case collecting_clear_unreachable_set: 3857db96d56Sopenharmony_ci next_value = NEXT_MASK_UNREACHABLE; 3867db96d56Sopenharmony_ci break; 3877db96d56Sopenharmony_ci case collecting_set_unreachable_set: 3887db96d56Sopenharmony_ci prev_value = PREV_MASK_COLLECTING; 3897db96d56Sopenharmony_ci next_value = NEXT_MASK_UNREACHABLE; 3907db96d56Sopenharmony_ci break; 3917db96d56Sopenharmony_ci default: 3927db96d56Sopenharmony_ci assert(! "bad internal flags argument"); 3937db96d56Sopenharmony_ci } 3947db96d56Sopenharmony_ci PyGC_Head *prev = head; 3957db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(head); 3967db96d56Sopenharmony_ci while (gc != head) { 3977db96d56Sopenharmony_ci PyGC_Head *trueprev = GC_PREV(gc); 3987db96d56Sopenharmony_ci PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE); 3997db96d56Sopenharmony_ci assert(truenext != NULL); 4007db96d56Sopenharmony_ci assert(trueprev == prev); 4017db96d56Sopenharmony_ci assert((gc->_gc_prev & PREV_MASK_COLLECTING) == prev_value); 4027db96d56Sopenharmony_ci assert((gc->_gc_next & NEXT_MASK_UNREACHABLE) == next_value); 4037db96d56Sopenharmony_ci prev = gc; 4047db96d56Sopenharmony_ci gc = truenext; 4057db96d56Sopenharmony_ci } 4067db96d56Sopenharmony_ci assert(prev == GC_PREV(head)); 4077db96d56Sopenharmony_ci} 4087db96d56Sopenharmony_ci#else 4097db96d56Sopenharmony_ci#define validate_list(x, y) do{}while(0) 4107db96d56Sopenharmony_ci#endif 4117db96d56Sopenharmony_ci 4127db96d56Sopenharmony_ci/*** end of list stuff ***/ 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_ci 4157db96d56Sopenharmony_ci/* Set all gc_refs = ob_refcnt. After this, gc_refs is > 0 and 4167db96d56Sopenharmony_ci * PREV_MASK_COLLECTING bit is set for all objects in containers. 4177db96d56Sopenharmony_ci */ 4187db96d56Sopenharmony_cistatic void 4197db96d56Sopenharmony_ciupdate_refs(PyGC_Head *containers) 4207db96d56Sopenharmony_ci{ 4217db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(containers); 4227db96d56Sopenharmony_ci for (; gc != containers; gc = GC_NEXT(gc)) { 4237db96d56Sopenharmony_ci gc_reset_refs(gc, Py_REFCNT(FROM_GC(gc))); 4247db96d56Sopenharmony_ci /* Python's cyclic gc should never see an incoming refcount 4257db96d56Sopenharmony_ci * of 0: if something decref'ed to 0, it should have been 4267db96d56Sopenharmony_ci * deallocated immediately at that time. 4277db96d56Sopenharmony_ci * Possible cause (if the assert triggers): a tp_dealloc 4287db96d56Sopenharmony_ci * routine left a gc-aware object tracked during its teardown 4297db96d56Sopenharmony_ci * phase, and did something-- or allowed something to happen -- 4307db96d56Sopenharmony_ci * that called back into Python. gc can trigger then, and may 4317db96d56Sopenharmony_ci * see the still-tracked dying object. Before this assert 4327db96d56Sopenharmony_ci * was added, such mistakes went on to allow gc to try to 4337db96d56Sopenharmony_ci * delete the object again. In a debug build, that caused 4347db96d56Sopenharmony_ci * a mysterious segfault, when _Py_ForgetReference tried 4357db96d56Sopenharmony_ci * to remove the object from the doubly-linked list of all 4367db96d56Sopenharmony_ci * objects a second time. In a release build, an actual 4377db96d56Sopenharmony_ci * double deallocation occurred, which leads to corruption 4387db96d56Sopenharmony_ci * of the allocator's internal bookkeeping pointers. That's 4397db96d56Sopenharmony_ci * so serious that maybe this should be a release-build 4407db96d56Sopenharmony_ci * check instead of an assert? 4417db96d56Sopenharmony_ci */ 4427db96d56Sopenharmony_ci _PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0); 4437db96d56Sopenharmony_ci } 4447db96d56Sopenharmony_ci} 4457db96d56Sopenharmony_ci 4467db96d56Sopenharmony_ci/* A traversal callback for subtract_refs. */ 4477db96d56Sopenharmony_cistatic int 4487db96d56Sopenharmony_civisit_decref(PyObject *op, void *parent) 4497db96d56Sopenharmony_ci{ 4507db96d56Sopenharmony_ci _PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op)); 4517db96d56Sopenharmony_ci 4527db96d56Sopenharmony_ci if (_PyObject_IS_GC(op)) { 4537db96d56Sopenharmony_ci PyGC_Head *gc = AS_GC(op); 4547db96d56Sopenharmony_ci /* We're only interested in gc_refs for objects in the 4557db96d56Sopenharmony_ci * generation being collected, which can be recognized 4567db96d56Sopenharmony_ci * because only they have positive gc_refs. 4577db96d56Sopenharmony_ci */ 4587db96d56Sopenharmony_ci if (gc_is_collecting(gc)) { 4597db96d56Sopenharmony_ci gc_decref(gc); 4607db96d56Sopenharmony_ci } 4617db96d56Sopenharmony_ci } 4627db96d56Sopenharmony_ci return 0; 4637db96d56Sopenharmony_ci} 4647db96d56Sopenharmony_ci 4657db96d56Sopenharmony_ci/* Subtract internal references from gc_refs. After this, gc_refs is >= 0 4667db96d56Sopenharmony_ci * for all objects in containers, and is GC_REACHABLE for all tracked gc 4677db96d56Sopenharmony_ci * objects not in containers. The ones with gc_refs > 0 are directly 4687db96d56Sopenharmony_ci * reachable from outside containers, and so can't be collected. 4697db96d56Sopenharmony_ci */ 4707db96d56Sopenharmony_cistatic void 4717db96d56Sopenharmony_cisubtract_refs(PyGC_Head *containers) 4727db96d56Sopenharmony_ci{ 4737db96d56Sopenharmony_ci traverseproc traverse; 4747db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(containers); 4757db96d56Sopenharmony_ci for (; gc != containers; gc = GC_NEXT(gc)) { 4767db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 4777db96d56Sopenharmony_ci traverse = Py_TYPE(op)->tp_traverse; 4787db96d56Sopenharmony_ci (void) traverse(op, 4797db96d56Sopenharmony_ci (visitproc)visit_decref, 4807db96d56Sopenharmony_ci op); 4817db96d56Sopenharmony_ci } 4827db96d56Sopenharmony_ci} 4837db96d56Sopenharmony_ci 4847db96d56Sopenharmony_ci/* A traversal callback for move_unreachable. */ 4857db96d56Sopenharmony_cistatic int 4867db96d56Sopenharmony_civisit_reachable(PyObject *op, PyGC_Head *reachable) 4877db96d56Sopenharmony_ci{ 4887db96d56Sopenharmony_ci if (!_PyObject_IS_GC(op)) { 4897db96d56Sopenharmony_ci return 0; 4907db96d56Sopenharmony_ci } 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci PyGC_Head *gc = AS_GC(op); 4937db96d56Sopenharmony_ci const Py_ssize_t gc_refs = gc_get_refs(gc); 4947db96d56Sopenharmony_ci 4957db96d56Sopenharmony_ci // Ignore objects in other generation. 4967db96d56Sopenharmony_ci // This also skips objects "to the left" of the current position in 4977db96d56Sopenharmony_ci // move_unreachable's scan of the 'young' list - they've already been 4987db96d56Sopenharmony_ci // traversed, and no longer have the PREV_MASK_COLLECTING flag. 4997db96d56Sopenharmony_ci if (! gc_is_collecting(gc)) { 5007db96d56Sopenharmony_ci return 0; 5017db96d56Sopenharmony_ci } 5027db96d56Sopenharmony_ci // It would be a logic error elsewhere if the collecting flag were set on 5037db96d56Sopenharmony_ci // an untracked object. 5047db96d56Sopenharmony_ci assert(gc->_gc_next != 0); 5057db96d56Sopenharmony_ci 5067db96d56Sopenharmony_ci if (gc->_gc_next & NEXT_MASK_UNREACHABLE) { 5077db96d56Sopenharmony_ci /* This had gc_refs = 0 when move_unreachable got 5087db96d56Sopenharmony_ci * to it, but turns out it's reachable after all. 5097db96d56Sopenharmony_ci * Move it back to move_unreachable's 'young' list, 5107db96d56Sopenharmony_ci * and move_unreachable will eventually get to it 5117db96d56Sopenharmony_ci * again. 5127db96d56Sopenharmony_ci */ 5137db96d56Sopenharmony_ci // Manually unlink gc from unreachable list because the list functions 5147db96d56Sopenharmony_ci // don't work right in the presence of NEXT_MASK_UNREACHABLE flags. 5157db96d56Sopenharmony_ci PyGC_Head *prev = GC_PREV(gc); 5167db96d56Sopenharmony_ci PyGC_Head *next = (PyGC_Head*)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE); 5177db96d56Sopenharmony_ci _PyObject_ASSERT(FROM_GC(prev), 5187db96d56Sopenharmony_ci prev->_gc_next & NEXT_MASK_UNREACHABLE); 5197db96d56Sopenharmony_ci _PyObject_ASSERT(FROM_GC(next), 5207db96d56Sopenharmony_ci next->_gc_next & NEXT_MASK_UNREACHABLE); 5217db96d56Sopenharmony_ci prev->_gc_next = gc->_gc_next; // copy NEXT_MASK_UNREACHABLE 5227db96d56Sopenharmony_ci _PyGCHead_SET_PREV(next, prev); 5237db96d56Sopenharmony_ci 5247db96d56Sopenharmony_ci gc_list_append(gc, reachable); 5257db96d56Sopenharmony_ci gc_set_refs(gc, 1); 5267db96d56Sopenharmony_ci } 5277db96d56Sopenharmony_ci else if (gc_refs == 0) { 5287db96d56Sopenharmony_ci /* This is in move_unreachable's 'young' list, but 5297db96d56Sopenharmony_ci * the traversal hasn't yet gotten to it. All 5307db96d56Sopenharmony_ci * we need to do is tell move_unreachable that it's 5317db96d56Sopenharmony_ci * reachable. 5327db96d56Sopenharmony_ci */ 5337db96d56Sopenharmony_ci gc_set_refs(gc, 1); 5347db96d56Sopenharmony_ci } 5357db96d56Sopenharmony_ci /* Else there's nothing to do. 5367db96d56Sopenharmony_ci * If gc_refs > 0, it must be in move_unreachable's 'young' 5377db96d56Sopenharmony_ci * list, and move_unreachable will eventually get to it. 5387db96d56Sopenharmony_ci */ 5397db96d56Sopenharmony_ci else { 5407db96d56Sopenharmony_ci _PyObject_ASSERT_WITH_MSG(op, gc_refs > 0, "refcount is too small"); 5417db96d56Sopenharmony_ci } 5427db96d56Sopenharmony_ci return 0; 5437db96d56Sopenharmony_ci} 5447db96d56Sopenharmony_ci 5457db96d56Sopenharmony_ci/* Move the unreachable objects from young to unreachable. After this, 5467db96d56Sopenharmony_ci * all objects in young don't have PREV_MASK_COLLECTING flag and 5477db96d56Sopenharmony_ci * unreachable have the flag. 5487db96d56Sopenharmony_ci * All objects in young after this are directly or indirectly reachable 5497db96d56Sopenharmony_ci * from outside the original young; and all objects in unreachable are 5507db96d56Sopenharmony_ci * not. 5517db96d56Sopenharmony_ci * 5527db96d56Sopenharmony_ci * This function restores _gc_prev pointer. young and unreachable are 5537db96d56Sopenharmony_ci * doubly linked list after this function. 5547db96d56Sopenharmony_ci * But _gc_next in unreachable list has NEXT_MASK_UNREACHABLE flag. 5557db96d56Sopenharmony_ci * So we can not gc_list_* functions for unreachable until we remove the flag. 5567db96d56Sopenharmony_ci */ 5577db96d56Sopenharmony_cistatic void 5587db96d56Sopenharmony_cimove_unreachable(PyGC_Head *young, PyGC_Head *unreachable) 5597db96d56Sopenharmony_ci{ 5607db96d56Sopenharmony_ci // previous elem in the young list, used for restore gc_prev. 5617db96d56Sopenharmony_ci PyGC_Head *prev = young; 5627db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(young); 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci /* Invariants: all objects "to the left" of us in young are reachable 5657db96d56Sopenharmony_ci * (directly or indirectly) from outside the young list as it was at entry. 5667db96d56Sopenharmony_ci * 5677db96d56Sopenharmony_ci * All other objects from the original young "to the left" of us are in 5687db96d56Sopenharmony_ci * unreachable now, and have NEXT_MASK_UNREACHABLE. All objects to the 5697db96d56Sopenharmony_ci * left of us in 'young' now have been scanned, and no objects here 5707db96d56Sopenharmony_ci * or to the right have been scanned yet. 5717db96d56Sopenharmony_ci */ 5727db96d56Sopenharmony_ci 5737db96d56Sopenharmony_ci while (gc != young) { 5747db96d56Sopenharmony_ci if (gc_get_refs(gc)) { 5757db96d56Sopenharmony_ci /* gc is definitely reachable from outside the 5767db96d56Sopenharmony_ci * original 'young'. Mark it as such, and traverse 5777db96d56Sopenharmony_ci * its pointers to find any other objects that may 5787db96d56Sopenharmony_ci * be directly reachable from it. Note that the 5797db96d56Sopenharmony_ci * call to tp_traverse may append objects to young, 5807db96d56Sopenharmony_ci * so we have to wait until it returns to determine 5817db96d56Sopenharmony_ci * the next object to visit. 5827db96d56Sopenharmony_ci */ 5837db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 5847db96d56Sopenharmony_ci traverseproc traverse = Py_TYPE(op)->tp_traverse; 5857db96d56Sopenharmony_ci _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(gc) > 0, 5867db96d56Sopenharmony_ci "refcount is too small"); 5877db96d56Sopenharmony_ci // NOTE: visit_reachable may change gc->_gc_next when 5887db96d56Sopenharmony_ci // young->_gc_prev == gc. Don't do gc = GC_NEXT(gc) before! 5897db96d56Sopenharmony_ci (void) traverse(op, 5907db96d56Sopenharmony_ci (visitproc)visit_reachable, 5917db96d56Sopenharmony_ci (void *)young); 5927db96d56Sopenharmony_ci // relink gc_prev to prev element. 5937db96d56Sopenharmony_ci _PyGCHead_SET_PREV(gc, prev); 5947db96d56Sopenharmony_ci // gc is not COLLECTING state after here. 5957db96d56Sopenharmony_ci gc_clear_collecting(gc); 5967db96d56Sopenharmony_ci prev = gc; 5977db96d56Sopenharmony_ci } 5987db96d56Sopenharmony_ci else { 5997db96d56Sopenharmony_ci /* This *may* be unreachable. To make progress, 6007db96d56Sopenharmony_ci * assume it is. gc isn't directly reachable from 6017db96d56Sopenharmony_ci * any object we've already traversed, but may be 6027db96d56Sopenharmony_ci * reachable from an object we haven't gotten to yet. 6037db96d56Sopenharmony_ci * visit_reachable will eventually move gc back into 6047db96d56Sopenharmony_ci * young if that's so, and we'll see it again. 6057db96d56Sopenharmony_ci */ 6067db96d56Sopenharmony_ci // Move gc to unreachable. 6077db96d56Sopenharmony_ci // No need to gc->next->prev = prev because it is single linked. 6087db96d56Sopenharmony_ci prev->_gc_next = gc->_gc_next; 6097db96d56Sopenharmony_ci 6107db96d56Sopenharmony_ci // We can't use gc_list_append() here because we use 6117db96d56Sopenharmony_ci // NEXT_MASK_UNREACHABLE here. 6127db96d56Sopenharmony_ci PyGC_Head *last = GC_PREV(unreachable); 6137db96d56Sopenharmony_ci // NOTE: Since all objects in unreachable set has 6147db96d56Sopenharmony_ci // NEXT_MASK_UNREACHABLE flag, we set it unconditionally. 6157db96d56Sopenharmony_ci // But this may pollute the unreachable list head's 'next' pointer 6167db96d56Sopenharmony_ci // too. That's semantically senseless but expedient here - the 6177db96d56Sopenharmony_ci // damage is repaired when this function ends. 6187db96d56Sopenharmony_ci last->_gc_next = (NEXT_MASK_UNREACHABLE | (uintptr_t)gc); 6197db96d56Sopenharmony_ci _PyGCHead_SET_PREV(gc, last); 6207db96d56Sopenharmony_ci gc->_gc_next = (NEXT_MASK_UNREACHABLE | (uintptr_t)unreachable); 6217db96d56Sopenharmony_ci unreachable->_gc_prev = (uintptr_t)gc; 6227db96d56Sopenharmony_ci } 6237db96d56Sopenharmony_ci gc = (PyGC_Head*)prev->_gc_next; 6247db96d56Sopenharmony_ci } 6257db96d56Sopenharmony_ci // young->_gc_prev must be last element remained in the list. 6267db96d56Sopenharmony_ci young->_gc_prev = (uintptr_t)prev; 6277db96d56Sopenharmony_ci // don't let the pollution of the list head's next pointer leak 6287db96d56Sopenharmony_ci unreachable->_gc_next &= ~NEXT_MASK_UNREACHABLE; 6297db96d56Sopenharmony_ci} 6307db96d56Sopenharmony_ci 6317db96d56Sopenharmony_cistatic void 6327db96d56Sopenharmony_ciuntrack_tuples(PyGC_Head *head) 6337db96d56Sopenharmony_ci{ 6347db96d56Sopenharmony_ci PyGC_Head *next, *gc = GC_NEXT(head); 6357db96d56Sopenharmony_ci while (gc != head) { 6367db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 6377db96d56Sopenharmony_ci next = GC_NEXT(gc); 6387db96d56Sopenharmony_ci if (PyTuple_CheckExact(op)) { 6397db96d56Sopenharmony_ci _PyTuple_MaybeUntrack(op); 6407db96d56Sopenharmony_ci } 6417db96d56Sopenharmony_ci gc = next; 6427db96d56Sopenharmony_ci } 6437db96d56Sopenharmony_ci} 6447db96d56Sopenharmony_ci 6457db96d56Sopenharmony_ci/* Try to untrack all currently tracked dictionaries */ 6467db96d56Sopenharmony_cistatic void 6477db96d56Sopenharmony_ciuntrack_dicts(PyGC_Head *head) 6487db96d56Sopenharmony_ci{ 6497db96d56Sopenharmony_ci PyGC_Head *next, *gc = GC_NEXT(head); 6507db96d56Sopenharmony_ci while (gc != head) { 6517db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 6527db96d56Sopenharmony_ci next = GC_NEXT(gc); 6537db96d56Sopenharmony_ci if (PyDict_CheckExact(op)) { 6547db96d56Sopenharmony_ci _PyDict_MaybeUntrack(op); 6557db96d56Sopenharmony_ci } 6567db96d56Sopenharmony_ci gc = next; 6577db96d56Sopenharmony_ci } 6587db96d56Sopenharmony_ci} 6597db96d56Sopenharmony_ci 6607db96d56Sopenharmony_ci/* Return true if object has a pre-PEP 442 finalization method. */ 6617db96d56Sopenharmony_cistatic int 6627db96d56Sopenharmony_cihas_legacy_finalizer(PyObject *op) 6637db96d56Sopenharmony_ci{ 6647db96d56Sopenharmony_ci return Py_TYPE(op)->tp_del != NULL; 6657db96d56Sopenharmony_ci} 6667db96d56Sopenharmony_ci 6677db96d56Sopenharmony_ci/* Move the objects in unreachable with tp_del slots into `finalizers`. 6687db96d56Sopenharmony_ci * 6697db96d56Sopenharmony_ci * This function also removes NEXT_MASK_UNREACHABLE flag 6707db96d56Sopenharmony_ci * from _gc_next in unreachable. 6717db96d56Sopenharmony_ci */ 6727db96d56Sopenharmony_cistatic void 6737db96d56Sopenharmony_cimove_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) 6747db96d56Sopenharmony_ci{ 6757db96d56Sopenharmony_ci PyGC_Head *gc, *next; 6767db96d56Sopenharmony_ci assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0); 6777db96d56Sopenharmony_ci 6787db96d56Sopenharmony_ci /* March over unreachable. Move objects with finalizers into 6797db96d56Sopenharmony_ci * `finalizers`. 6807db96d56Sopenharmony_ci */ 6817db96d56Sopenharmony_ci for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) { 6827db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 6837db96d56Sopenharmony_ci 6847db96d56Sopenharmony_ci _PyObject_ASSERT(op, gc->_gc_next & NEXT_MASK_UNREACHABLE); 6857db96d56Sopenharmony_ci gc->_gc_next &= ~NEXT_MASK_UNREACHABLE; 6867db96d56Sopenharmony_ci next = (PyGC_Head*)gc->_gc_next; 6877db96d56Sopenharmony_ci 6887db96d56Sopenharmony_ci if (has_legacy_finalizer(op)) { 6897db96d56Sopenharmony_ci gc_clear_collecting(gc); 6907db96d56Sopenharmony_ci gc_list_move(gc, finalizers); 6917db96d56Sopenharmony_ci } 6927db96d56Sopenharmony_ci } 6937db96d56Sopenharmony_ci} 6947db96d56Sopenharmony_ci 6957db96d56Sopenharmony_cistatic inline void 6967db96d56Sopenharmony_ciclear_unreachable_mask(PyGC_Head *unreachable) 6977db96d56Sopenharmony_ci{ 6987db96d56Sopenharmony_ci /* Check that the list head does not have the unreachable bit set */ 6997db96d56Sopenharmony_ci assert(((uintptr_t)unreachable & NEXT_MASK_UNREACHABLE) == 0); 7007db96d56Sopenharmony_ci 7017db96d56Sopenharmony_ci PyGC_Head *gc, *next; 7027db96d56Sopenharmony_ci assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0); 7037db96d56Sopenharmony_ci for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) { 7047db96d56Sopenharmony_ci _PyObject_ASSERT((PyObject*)FROM_GC(gc), gc->_gc_next & NEXT_MASK_UNREACHABLE); 7057db96d56Sopenharmony_ci gc->_gc_next &= ~NEXT_MASK_UNREACHABLE; 7067db96d56Sopenharmony_ci next = (PyGC_Head*)gc->_gc_next; 7077db96d56Sopenharmony_ci } 7087db96d56Sopenharmony_ci validate_list(unreachable, collecting_set_unreachable_clear); 7097db96d56Sopenharmony_ci} 7107db96d56Sopenharmony_ci 7117db96d56Sopenharmony_ci/* A traversal callback for move_legacy_finalizer_reachable. */ 7127db96d56Sopenharmony_cistatic int 7137db96d56Sopenharmony_civisit_move(PyObject *op, PyGC_Head *tolist) 7147db96d56Sopenharmony_ci{ 7157db96d56Sopenharmony_ci if (_PyObject_IS_GC(op)) { 7167db96d56Sopenharmony_ci PyGC_Head *gc = AS_GC(op); 7177db96d56Sopenharmony_ci if (gc_is_collecting(gc)) { 7187db96d56Sopenharmony_ci gc_list_move(gc, tolist); 7197db96d56Sopenharmony_ci gc_clear_collecting(gc); 7207db96d56Sopenharmony_ci } 7217db96d56Sopenharmony_ci } 7227db96d56Sopenharmony_ci return 0; 7237db96d56Sopenharmony_ci} 7247db96d56Sopenharmony_ci 7257db96d56Sopenharmony_ci/* Move objects that are reachable from finalizers, from the unreachable set 7267db96d56Sopenharmony_ci * into finalizers set. 7277db96d56Sopenharmony_ci */ 7287db96d56Sopenharmony_cistatic void 7297db96d56Sopenharmony_cimove_legacy_finalizer_reachable(PyGC_Head *finalizers) 7307db96d56Sopenharmony_ci{ 7317db96d56Sopenharmony_ci traverseproc traverse; 7327db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(finalizers); 7337db96d56Sopenharmony_ci for (; gc != finalizers; gc = GC_NEXT(gc)) { 7347db96d56Sopenharmony_ci /* Note that the finalizers list may grow during this. */ 7357db96d56Sopenharmony_ci traverse = Py_TYPE(FROM_GC(gc))->tp_traverse; 7367db96d56Sopenharmony_ci (void) traverse(FROM_GC(gc), 7377db96d56Sopenharmony_ci (visitproc)visit_move, 7387db96d56Sopenharmony_ci (void *)finalizers); 7397db96d56Sopenharmony_ci } 7407db96d56Sopenharmony_ci} 7417db96d56Sopenharmony_ci 7427db96d56Sopenharmony_ci/* Clear all weakrefs to unreachable objects, and if such a weakref has a 7437db96d56Sopenharmony_ci * callback, invoke it if necessary. Note that it's possible for such 7447db96d56Sopenharmony_ci * weakrefs to be outside the unreachable set -- indeed, those are precisely 7457db96d56Sopenharmony_ci * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for 7467db96d56Sopenharmony_ci * overview & some details. Some weakrefs with callbacks may be reclaimed 7477db96d56Sopenharmony_ci * directly by this routine; the number reclaimed is the return value. Other 7487db96d56Sopenharmony_ci * weakrefs with callbacks may be moved into the `old` generation. Objects 7497db96d56Sopenharmony_ci * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in 7507db96d56Sopenharmony_ci * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, 7517db96d56Sopenharmony_ci * no object in `unreachable` is weakly referenced anymore. 7527db96d56Sopenharmony_ci */ 7537db96d56Sopenharmony_cistatic int 7547db96d56Sopenharmony_cihandle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) 7557db96d56Sopenharmony_ci{ 7567db96d56Sopenharmony_ci PyGC_Head *gc; 7577db96d56Sopenharmony_ci PyObject *op; /* generally FROM_GC(gc) */ 7587db96d56Sopenharmony_ci PyWeakReference *wr; /* generally a cast of op */ 7597db96d56Sopenharmony_ci PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ 7607db96d56Sopenharmony_ci PyGC_Head *next; 7617db96d56Sopenharmony_ci int num_freed = 0; 7627db96d56Sopenharmony_ci 7637db96d56Sopenharmony_ci gc_list_init(&wrcb_to_call); 7647db96d56Sopenharmony_ci 7657db96d56Sopenharmony_ci /* Clear all weakrefs to the objects in unreachable. If such a weakref 7667db96d56Sopenharmony_ci * also has a callback, move it into `wrcb_to_call` if the callback 7677db96d56Sopenharmony_ci * needs to be invoked. Note that we cannot invoke any callbacks until 7687db96d56Sopenharmony_ci * all weakrefs to unreachable objects are cleared, lest the callback 7697db96d56Sopenharmony_ci * resurrect an unreachable object via a still-active weakref. We 7707db96d56Sopenharmony_ci * make another pass over wrcb_to_call, invoking callbacks, after this 7717db96d56Sopenharmony_ci * pass completes. 7727db96d56Sopenharmony_ci */ 7737db96d56Sopenharmony_ci for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) { 7747db96d56Sopenharmony_ci PyWeakReference **wrlist; 7757db96d56Sopenharmony_ci 7767db96d56Sopenharmony_ci op = FROM_GC(gc); 7777db96d56Sopenharmony_ci next = GC_NEXT(gc); 7787db96d56Sopenharmony_ci 7797db96d56Sopenharmony_ci if (PyWeakref_Check(op)) { 7807db96d56Sopenharmony_ci /* A weakref inside the unreachable set must be cleared. If we 7817db96d56Sopenharmony_ci * allow its callback to execute inside delete_garbage(), it 7827db96d56Sopenharmony_ci * could expose objects that have tp_clear already called on 7837db96d56Sopenharmony_ci * them. Or, it could resurrect unreachable objects. One way 7847db96d56Sopenharmony_ci * this can happen is if some container objects do not implement 7857db96d56Sopenharmony_ci * tp_traverse. Then, wr_object can be outside the unreachable 7867db96d56Sopenharmony_ci * set but can be deallocated as a result of breaking the 7877db96d56Sopenharmony_ci * reference cycle. If we don't clear the weakref, the callback 7887db96d56Sopenharmony_ci * will run and potentially cause a crash. See bpo-38006 for 7897db96d56Sopenharmony_ci * one example. 7907db96d56Sopenharmony_ci */ 7917db96d56Sopenharmony_ci _PyWeakref_ClearRef((PyWeakReference *)op); 7927db96d56Sopenharmony_ci } 7937db96d56Sopenharmony_ci 7947db96d56Sopenharmony_ci if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op))) 7957db96d56Sopenharmony_ci continue; 7967db96d56Sopenharmony_ci 7977db96d56Sopenharmony_ci /* It supports weakrefs. Does it have any? */ 7987db96d56Sopenharmony_ci wrlist = (PyWeakReference **) 7997db96d56Sopenharmony_ci _PyObject_GET_WEAKREFS_LISTPTR(op); 8007db96d56Sopenharmony_ci 8017db96d56Sopenharmony_ci /* `op` may have some weakrefs. March over the list, clear 8027db96d56Sopenharmony_ci * all the weakrefs, and move the weakrefs with callbacks 8037db96d56Sopenharmony_ci * that must be called into wrcb_to_call. 8047db96d56Sopenharmony_ci */ 8057db96d56Sopenharmony_ci for (wr = *wrlist; wr != NULL; wr = *wrlist) { 8067db96d56Sopenharmony_ci PyGC_Head *wrasgc; /* AS_GC(wr) */ 8077db96d56Sopenharmony_ci 8087db96d56Sopenharmony_ci /* _PyWeakref_ClearRef clears the weakref but leaves 8097db96d56Sopenharmony_ci * the callback pointer intact. Obscure: it also 8107db96d56Sopenharmony_ci * changes *wrlist. 8117db96d56Sopenharmony_ci */ 8127db96d56Sopenharmony_ci _PyObject_ASSERT((PyObject *)wr, wr->wr_object == op); 8137db96d56Sopenharmony_ci _PyWeakref_ClearRef(wr); 8147db96d56Sopenharmony_ci _PyObject_ASSERT((PyObject *)wr, wr->wr_object == Py_None); 8157db96d56Sopenharmony_ci if (wr->wr_callback == NULL) { 8167db96d56Sopenharmony_ci /* no callback */ 8177db96d56Sopenharmony_ci continue; 8187db96d56Sopenharmony_ci } 8197db96d56Sopenharmony_ci 8207db96d56Sopenharmony_ci /* Headache time. `op` is going away, and is weakly referenced by 8217db96d56Sopenharmony_ci * `wr`, which has a callback. Should the callback be invoked? If wr 8227db96d56Sopenharmony_ci * is also trash, no: 8237db96d56Sopenharmony_ci * 8247db96d56Sopenharmony_ci * 1. There's no need to call it. The object and the weakref are 8257db96d56Sopenharmony_ci * both going away, so it's legitimate to pretend the weakref is 8267db96d56Sopenharmony_ci * going away first. The user has to ensure a weakref outlives its 8277db96d56Sopenharmony_ci * referent if they want a guarantee that the wr callback will get 8287db96d56Sopenharmony_ci * invoked. 8297db96d56Sopenharmony_ci * 8307db96d56Sopenharmony_ci * 2. It may be catastrophic to call it. If the callback is also in 8317db96d56Sopenharmony_ci * cyclic trash (CT), then although the CT is unreachable from 8327db96d56Sopenharmony_ci * outside the current generation, CT may be reachable from the 8337db96d56Sopenharmony_ci * callback. Then the callback could resurrect insane objects. 8347db96d56Sopenharmony_ci * 8357db96d56Sopenharmony_ci * Since the callback is never needed and may be unsafe in this case, 8367db96d56Sopenharmony_ci * wr is simply left in the unreachable set. Note that because we 8377db96d56Sopenharmony_ci * already called _PyWeakref_ClearRef(wr), its callback will never 8387db96d56Sopenharmony_ci * trigger. 8397db96d56Sopenharmony_ci * 8407db96d56Sopenharmony_ci * OTOH, if wr isn't part of CT, we should invoke the callback: the 8417db96d56Sopenharmony_ci * weakref outlived the trash. Note that since wr isn't CT in this 8427db96d56Sopenharmony_ci * case, its callback can't be CT either -- wr acted as an external 8437db96d56Sopenharmony_ci * root to this generation, and therefore its callback did too. So 8447db96d56Sopenharmony_ci * nothing in CT is reachable from the callback either, so it's hard 8457db96d56Sopenharmony_ci * to imagine how calling it later could create a problem for us. wr 8467db96d56Sopenharmony_ci * is moved to wrcb_to_call in this case. 8477db96d56Sopenharmony_ci */ 8487db96d56Sopenharmony_ci if (gc_is_collecting(AS_GC(wr))) { 8497db96d56Sopenharmony_ci /* it should already have been cleared above */ 8507db96d56Sopenharmony_ci assert(wr->wr_object == Py_None); 8517db96d56Sopenharmony_ci continue; 8527db96d56Sopenharmony_ci } 8537db96d56Sopenharmony_ci 8547db96d56Sopenharmony_ci /* Create a new reference so that wr can't go away 8557db96d56Sopenharmony_ci * before we can process it again. 8567db96d56Sopenharmony_ci */ 8577db96d56Sopenharmony_ci Py_INCREF(wr); 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci /* Move wr to wrcb_to_call, for the next pass. */ 8607db96d56Sopenharmony_ci wrasgc = AS_GC(wr); 8617db96d56Sopenharmony_ci assert(wrasgc != next); /* wrasgc is reachable, but 8627db96d56Sopenharmony_ci next isn't, so they can't 8637db96d56Sopenharmony_ci be the same */ 8647db96d56Sopenharmony_ci gc_list_move(wrasgc, &wrcb_to_call); 8657db96d56Sopenharmony_ci } 8667db96d56Sopenharmony_ci } 8677db96d56Sopenharmony_ci 8687db96d56Sopenharmony_ci /* Invoke the callbacks we decided to honor. It's safe to invoke them 8697db96d56Sopenharmony_ci * because they can't reference unreachable objects. 8707db96d56Sopenharmony_ci */ 8717db96d56Sopenharmony_ci while (! gc_list_is_empty(&wrcb_to_call)) { 8727db96d56Sopenharmony_ci PyObject *temp; 8737db96d56Sopenharmony_ci PyObject *callback; 8747db96d56Sopenharmony_ci 8757db96d56Sopenharmony_ci gc = (PyGC_Head*)wrcb_to_call._gc_next; 8767db96d56Sopenharmony_ci op = FROM_GC(gc); 8777db96d56Sopenharmony_ci _PyObject_ASSERT(op, PyWeakref_Check(op)); 8787db96d56Sopenharmony_ci wr = (PyWeakReference *)op; 8797db96d56Sopenharmony_ci callback = wr->wr_callback; 8807db96d56Sopenharmony_ci _PyObject_ASSERT(op, callback != NULL); 8817db96d56Sopenharmony_ci 8827db96d56Sopenharmony_ci /* copy-paste of weakrefobject.c's handle_callback() */ 8837db96d56Sopenharmony_ci temp = PyObject_CallOneArg(callback, (PyObject *)wr); 8847db96d56Sopenharmony_ci if (temp == NULL) 8857db96d56Sopenharmony_ci PyErr_WriteUnraisable(callback); 8867db96d56Sopenharmony_ci else 8877db96d56Sopenharmony_ci Py_DECREF(temp); 8887db96d56Sopenharmony_ci 8897db96d56Sopenharmony_ci /* Give up the reference we created in the first pass. When 8907db96d56Sopenharmony_ci * op's refcount hits 0 (which it may or may not do right now), 8917db96d56Sopenharmony_ci * op's tp_dealloc will decref op->wr_callback too. Note 8927db96d56Sopenharmony_ci * that the refcount probably will hit 0 now, and because this 8937db96d56Sopenharmony_ci * weakref was reachable to begin with, gc didn't already 8947db96d56Sopenharmony_ci * add it to its count of freed objects. Example: a reachable 8957db96d56Sopenharmony_ci * weak value dict maps some key to this reachable weakref. 8967db96d56Sopenharmony_ci * The callback removes this key->weakref mapping from the 8977db96d56Sopenharmony_ci * dict, leaving no other references to the weakref (excepting 8987db96d56Sopenharmony_ci * ours). 8997db96d56Sopenharmony_ci */ 9007db96d56Sopenharmony_ci Py_DECREF(op); 9017db96d56Sopenharmony_ci if (wrcb_to_call._gc_next == (uintptr_t)gc) { 9027db96d56Sopenharmony_ci /* object is still alive -- move it */ 9037db96d56Sopenharmony_ci gc_list_move(gc, old); 9047db96d56Sopenharmony_ci } 9057db96d56Sopenharmony_ci else { 9067db96d56Sopenharmony_ci ++num_freed; 9077db96d56Sopenharmony_ci } 9087db96d56Sopenharmony_ci } 9097db96d56Sopenharmony_ci 9107db96d56Sopenharmony_ci return num_freed; 9117db96d56Sopenharmony_ci} 9127db96d56Sopenharmony_ci 9137db96d56Sopenharmony_cistatic void 9147db96d56Sopenharmony_cidebug_cycle(const char *msg, PyObject *op) 9157db96d56Sopenharmony_ci{ 9167db96d56Sopenharmony_ci PySys_FormatStderr("gc: %s <%s %p>\n", 9177db96d56Sopenharmony_ci msg, Py_TYPE(op)->tp_name, op); 9187db96d56Sopenharmony_ci} 9197db96d56Sopenharmony_ci 9207db96d56Sopenharmony_ci/* Handle uncollectable garbage (cycles with tp_del slots, and stuff reachable 9217db96d56Sopenharmony_ci * only from such cycles). 9227db96d56Sopenharmony_ci * If DEBUG_SAVEALL, all objects in finalizers are appended to the module 9237db96d56Sopenharmony_ci * garbage list (a Python list), else only the objects in finalizers with 9247db96d56Sopenharmony_ci * __del__ methods are appended to garbage. All objects in finalizers are 9257db96d56Sopenharmony_ci * merged into the old list regardless. 9267db96d56Sopenharmony_ci */ 9277db96d56Sopenharmony_cistatic void 9287db96d56Sopenharmony_cihandle_legacy_finalizers(PyThreadState *tstate, 9297db96d56Sopenharmony_ci GCState *gcstate, 9307db96d56Sopenharmony_ci PyGC_Head *finalizers, PyGC_Head *old) 9317db96d56Sopenharmony_ci{ 9327db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 9337db96d56Sopenharmony_ci assert(gcstate->garbage != NULL); 9347db96d56Sopenharmony_ci 9357db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(finalizers); 9367db96d56Sopenharmony_ci for (; gc != finalizers; gc = GC_NEXT(gc)) { 9377db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 9387db96d56Sopenharmony_ci 9397db96d56Sopenharmony_ci if ((gcstate->debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) { 9407db96d56Sopenharmony_ci if (PyList_Append(gcstate->garbage, op) < 0) { 9417db96d56Sopenharmony_ci _PyErr_Clear(tstate); 9427db96d56Sopenharmony_ci break; 9437db96d56Sopenharmony_ci } 9447db96d56Sopenharmony_ci } 9457db96d56Sopenharmony_ci } 9467db96d56Sopenharmony_ci 9477db96d56Sopenharmony_ci gc_list_merge(finalizers, old); 9487db96d56Sopenharmony_ci} 9497db96d56Sopenharmony_ci 9507db96d56Sopenharmony_ci/* Run first-time finalizers (if any) on all the objects in collectable. 9517db96d56Sopenharmony_ci * Note that this may remove some (or even all) of the objects from the 9527db96d56Sopenharmony_ci * list, due to refcounts falling to 0. 9537db96d56Sopenharmony_ci */ 9547db96d56Sopenharmony_cistatic void 9557db96d56Sopenharmony_cifinalize_garbage(PyThreadState *tstate, PyGC_Head *collectable) 9567db96d56Sopenharmony_ci{ 9577db96d56Sopenharmony_ci destructor finalize; 9587db96d56Sopenharmony_ci PyGC_Head seen; 9597db96d56Sopenharmony_ci 9607db96d56Sopenharmony_ci /* While we're going through the loop, `finalize(op)` may cause op, or 9617db96d56Sopenharmony_ci * other objects, to be reclaimed via refcounts falling to zero. So 9627db96d56Sopenharmony_ci * there's little we can rely on about the structure of the input 9637db96d56Sopenharmony_ci * `collectable` list across iterations. For safety, we always take the 9647db96d56Sopenharmony_ci * first object in that list and move it to a temporary `seen` list. 9657db96d56Sopenharmony_ci * If objects vanish from the `collectable` and `seen` lists we don't 9667db96d56Sopenharmony_ci * care. 9677db96d56Sopenharmony_ci */ 9687db96d56Sopenharmony_ci gc_list_init(&seen); 9697db96d56Sopenharmony_ci 9707db96d56Sopenharmony_ci while (!gc_list_is_empty(collectable)) { 9717db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(collectable); 9727db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 9737db96d56Sopenharmony_ci gc_list_move(gc, &seen); 9747db96d56Sopenharmony_ci if (!_PyGCHead_FINALIZED(gc) && 9757db96d56Sopenharmony_ci (finalize = Py_TYPE(op)->tp_finalize) != NULL) { 9767db96d56Sopenharmony_ci _PyGCHead_SET_FINALIZED(gc); 9777db96d56Sopenharmony_ci Py_INCREF(op); 9787db96d56Sopenharmony_ci finalize(op); 9797db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 9807db96d56Sopenharmony_ci Py_DECREF(op); 9817db96d56Sopenharmony_ci } 9827db96d56Sopenharmony_ci } 9837db96d56Sopenharmony_ci gc_list_merge(&seen, collectable); 9847db96d56Sopenharmony_ci} 9857db96d56Sopenharmony_ci 9867db96d56Sopenharmony_ci/* Break reference cycles by clearing the containers involved. This is 9877db96d56Sopenharmony_ci * tricky business as the lists can be changing and we don't know which 9887db96d56Sopenharmony_ci * objects may be freed. It is possible I screwed something up here. 9897db96d56Sopenharmony_ci */ 9907db96d56Sopenharmony_cistatic void 9917db96d56Sopenharmony_cidelete_garbage(PyThreadState *tstate, GCState *gcstate, 9927db96d56Sopenharmony_ci PyGC_Head *collectable, PyGC_Head *old) 9937db96d56Sopenharmony_ci{ 9947db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 9957db96d56Sopenharmony_ci 9967db96d56Sopenharmony_ci while (!gc_list_is_empty(collectable)) { 9977db96d56Sopenharmony_ci PyGC_Head *gc = GC_NEXT(collectable); 9987db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 9997db96d56Sopenharmony_ci 10007db96d56Sopenharmony_ci _PyObject_ASSERT_WITH_MSG(op, Py_REFCNT(op) > 0, 10017db96d56Sopenharmony_ci "refcount is too small"); 10027db96d56Sopenharmony_ci 10037db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_SAVEALL) { 10047db96d56Sopenharmony_ci assert(gcstate->garbage != NULL); 10057db96d56Sopenharmony_ci if (PyList_Append(gcstate->garbage, op) < 0) { 10067db96d56Sopenharmony_ci _PyErr_Clear(tstate); 10077db96d56Sopenharmony_ci } 10087db96d56Sopenharmony_ci } 10097db96d56Sopenharmony_ci else { 10107db96d56Sopenharmony_ci inquiry clear; 10117db96d56Sopenharmony_ci if ((clear = Py_TYPE(op)->tp_clear) != NULL) { 10127db96d56Sopenharmony_ci Py_INCREF(op); 10137db96d56Sopenharmony_ci (void) clear(op); 10147db96d56Sopenharmony_ci if (_PyErr_Occurred(tstate)) { 10157db96d56Sopenharmony_ci _PyErr_WriteUnraisableMsg("in tp_clear of", 10167db96d56Sopenharmony_ci (PyObject*)Py_TYPE(op)); 10177db96d56Sopenharmony_ci } 10187db96d56Sopenharmony_ci Py_DECREF(op); 10197db96d56Sopenharmony_ci } 10207db96d56Sopenharmony_ci } 10217db96d56Sopenharmony_ci if (GC_NEXT(collectable) == gc) { 10227db96d56Sopenharmony_ci /* object is still alive, move it, it may die later */ 10237db96d56Sopenharmony_ci gc_clear_collecting(gc); 10247db96d56Sopenharmony_ci gc_list_move(gc, old); 10257db96d56Sopenharmony_ci } 10267db96d56Sopenharmony_ci } 10277db96d56Sopenharmony_ci} 10287db96d56Sopenharmony_ci 10297db96d56Sopenharmony_ci/* Clear all free lists 10307db96d56Sopenharmony_ci * All free lists are cleared during the collection of the highest generation. 10317db96d56Sopenharmony_ci * Allocated items in the free list may keep a pymalloc arena occupied. 10327db96d56Sopenharmony_ci * Clearing the free lists may give back memory to the OS earlier. 10337db96d56Sopenharmony_ci */ 10347db96d56Sopenharmony_cistatic void 10357db96d56Sopenharmony_ciclear_freelists(PyInterpreterState *interp) 10367db96d56Sopenharmony_ci{ 10377db96d56Sopenharmony_ci _PyTuple_ClearFreeList(interp); 10387db96d56Sopenharmony_ci _PyFloat_ClearFreeList(interp); 10397db96d56Sopenharmony_ci _PyList_ClearFreeList(interp); 10407db96d56Sopenharmony_ci _PyDict_ClearFreeList(interp); 10417db96d56Sopenharmony_ci _PyAsyncGen_ClearFreeLists(interp); 10427db96d56Sopenharmony_ci _PyContext_ClearFreeList(interp); 10437db96d56Sopenharmony_ci} 10447db96d56Sopenharmony_ci 10457db96d56Sopenharmony_ci// Show stats for objects in each generations 10467db96d56Sopenharmony_cistatic void 10477db96d56Sopenharmony_cishow_stats_each_generations(GCState *gcstate) 10487db96d56Sopenharmony_ci{ 10497db96d56Sopenharmony_ci char buf[100]; 10507db96d56Sopenharmony_ci size_t pos = 0; 10517db96d56Sopenharmony_ci 10527db96d56Sopenharmony_ci for (int i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) { 10537db96d56Sopenharmony_ci pos += PyOS_snprintf(buf+pos, sizeof(buf)-pos, 10547db96d56Sopenharmony_ci " %zd", 10557db96d56Sopenharmony_ci gc_list_size(GEN_HEAD(gcstate, i))); 10567db96d56Sopenharmony_ci } 10577db96d56Sopenharmony_ci 10587db96d56Sopenharmony_ci PySys_FormatStderr( 10597db96d56Sopenharmony_ci "gc: objects in each generation:%s\n" 10607db96d56Sopenharmony_ci "gc: objects in permanent generation: %zd\n", 10617db96d56Sopenharmony_ci buf, gc_list_size(&gcstate->permanent_generation.head)); 10627db96d56Sopenharmony_ci} 10637db96d56Sopenharmony_ci 10647db96d56Sopenharmony_ci/* Deduce which objects among "base" are unreachable from outside the list 10657db96d56Sopenharmony_ci and move them to 'unreachable'. The process consist in the following steps: 10667db96d56Sopenharmony_ci 10677db96d56Sopenharmony_ci1. Copy all reference counts to a different field (gc_prev is used to hold 10687db96d56Sopenharmony_ci this copy to save memory). 10697db96d56Sopenharmony_ci2. Traverse all objects in "base" and visit all referred objects using 10707db96d56Sopenharmony_ci "tp_traverse" and for every visited object, subtract 1 to the reference 10717db96d56Sopenharmony_ci count (the one that we copied in the previous step). After this step, all 10727db96d56Sopenharmony_ci objects that can be reached directly from outside must have strictly positive 10737db96d56Sopenharmony_ci reference count, while all unreachable objects must have a count of exactly 0. 10747db96d56Sopenharmony_ci3. Identify all unreachable objects (the ones with 0 reference count) and move 10757db96d56Sopenharmony_ci them to the "unreachable" list. This step also needs to move back to "base" all 10767db96d56Sopenharmony_ci objects that were initially marked as unreachable but are referred transitively 10777db96d56Sopenharmony_ci by the reachable objects (the ones with strictly positive reference count). 10787db96d56Sopenharmony_ci 10797db96d56Sopenharmony_ciContracts: 10807db96d56Sopenharmony_ci 10817db96d56Sopenharmony_ci * The "base" has to be a valid list with no mask set. 10827db96d56Sopenharmony_ci 10837db96d56Sopenharmony_ci * The "unreachable" list must be uninitialized (this function calls 10847db96d56Sopenharmony_ci gc_list_init over 'unreachable'). 10857db96d56Sopenharmony_ci 10867db96d56Sopenharmony_ciIMPORTANT: This function leaves 'unreachable' with the NEXT_MASK_UNREACHABLE 10877db96d56Sopenharmony_ciflag set but it does not clear it to skip unnecessary iteration. Before the 10887db96d56Sopenharmony_ciflag is cleared (for example, by using 'clear_unreachable_mask' function or 10897db96d56Sopenharmony_ciby a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal 10907db96d56Sopenharmony_cilist and we can not use most gc_list_* functions for it. */ 10917db96d56Sopenharmony_cistatic inline void 10927db96d56Sopenharmony_cideduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) { 10937db96d56Sopenharmony_ci validate_list(base, collecting_clear_unreachable_clear); 10947db96d56Sopenharmony_ci /* Using ob_refcnt and gc_refs, calculate which objects in the 10957db96d56Sopenharmony_ci * container set are reachable from outside the set (i.e., have a 10967db96d56Sopenharmony_ci * refcount greater than 0 when all the references within the 10977db96d56Sopenharmony_ci * set are taken into account). 10987db96d56Sopenharmony_ci */ 10997db96d56Sopenharmony_ci update_refs(base); // gc_prev is used for gc_refs 11007db96d56Sopenharmony_ci subtract_refs(base); 11017db96d56Sopenharmony_ci 11027db96d56Sopenharmony_ci /* Leave everything reachable from outside base in base, and move 11037db96d56Sopenharmony_ci * everything else (in base) to unreachable. 11047db96d56Sopenharmony_ci * 11057db96d56Sopenharmony_ci * NOTE: This used to move the reachable objects into a reachable 11067db96d56Sopenharmony_ci * set instead. But most things usually turn out to be reachable, 11077db96d56Sopenharmony_ci * so it's more efficient to move the unreachable things. It "sounds slick" 11087db96d56Sopenharmony_ci * to move the unreachable objects, until you think about it - the reason it 11097db96d56Sopenharmony_ci * pays isn't actually obvious. 11107db96d56Sopenharmony_ci * 11117db96d56Sopenharmony_ci * Suppose we create objects A, B, C in that order. They appear in the young 11127db96d56Sopenharmony_ci * generation in the same order. If B points to A, and C to B, and C is 11137db96d56Sopenharmony_ci * reachable from outside, then the adjusted refcounts will be 0, 0, and 1 11147db96d56Sopenharmony_ci * respectively. 11157db96d56Sopenharmony_ci * 11167db96d56Sopenharmony_ci * When move_unreachable finds A, A is moved to the unreachable list. The 11177db96d56Sopenharmony_ci * same for B when it's first encountered. Then C is traversed, B is moved 11187db96d56Sopenharmony_ci * _back_ to the reachable list. B is eventually traversed, and then A is 11197db96d56Sopenharmony_ci * moved back to the reachable list. 11207db96d56Sopenharmony_ci * 11217db96d56Sopenharmony_ci * So instead of not moving at all, the reachable objects B and A are moved 11227db96d56Sopenharmony_ci * twice each. Why is this a win? A straightforward algorithm to move the 11237db96d56Sopenharmony_ci * reachable objects instead would move A, B, and C once each. 11247db96d56Sopenharmony_ci * 11257db96d56Sopenharmony_ci * The key is that this dance leaves the objects in order C, B, A - it's 11267db96d56Sopenharmony_ci * reversed from the original order. On all _subsequent_ scans, none of 11277db96d56Sopenharmony_ci * them will move. Since most objects aren't in cycles, this can save an 11287db96d56Sopenharmony_ci * unbounded number of moves across an unbounded number of later collections. 11297db96d56Sopenharmony_ci * It can cost more only the first time the chain is scanned. 11307db96d56Sopenharmony_ci * 11317db96d56Sopenharmony_ci * Drawback: move_unreachable is also used to find out what's still trash 11327db96d56Sopenharmony_ci * after finalizers may resurrect objects. In _that_ case most unreachable 11337db96d56Sopenharmony_ci * objects will remain unreachable, so it would be more efficient to move 11347db96d56Sopenharmony_ci * the reachable objects instead. But this is a one-time cost, probably not 11357db96d56Sopenharmony_ci * worth complicating the code to speed just a little. 11367db96d56Sopenharmony_ci */ 11377db96d56Sopenharmony_ci gc_list_init(unreachable); 11387db96d56Sopenharmony_ci move_unreachable(base, unreachable); // gc_prev is pointer again 11397db96d56Sopenharmony_ci validate_list(base, collecting_clear_unreachable_clear); 11407db96d56Sopenharmony_ci validate_list(unreachable, collecting_set_unreachable_set); 11417db96d56Sopenharmony_ci} 11427db96d56Sopenharmony_ci 11437db96d56Sopenharmony_ci/* Handle objects that may have resurrected after a call to 'finalize_garbage', moving 11447db96d56Sopenharmony_ci them to 'old_generation' and placing the rest on 'still_unreachable'. 11457db96d56Sopenharmony_ci 11467db96d56Sopenharmony_ci Contracts: 11477db96d56Sopenharmony_ci * After this function 'unreachable' must not be used anymore and 'still_unreachable' 11487db96d56Sopenharmony_ci will contain the objects that did not resurrect. 11497db96d56Sopenharmony_ci 11507db96d56Sopenharmony_ci * The "still_unreachable" list must be uninitialized (this function calls 11517db96d56Sopenharmony_ci gc_list_init over 'still_unreachable'). 11527db96d56Sopenharmony_ci 11537db96d56Sopenharmony_ciIMPORTANT: After a call to this function, the 'still_unreachable' set will have the 11547db96d56Sopenharmony_ciPREV_MARK_COLLECTING set, but the objects in this set are going to be removed so 11557db96d56Sopenharmony_ciwe can skip the expense of clearing the flag to avoid extra iteration. */ 11567db96d56Sopenharmony_cistatic inline void 11577db96d56Sopenharmony_cihandle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, 11587db96d56Sopenharmony_ci PyGC_Head *old_generation) 11597db96d56Sopenharmony_ci{ 11607db96d56Sopenharmony_ci // Remove the PREV_MASK_COLLECTING from unreachable 11617db96d56Sopenharmony_ci // to prepare it for a new call to 'deduce_unreachable' 11627db96d56Sopenharmony_ci gc_list_clear_collecting(unreachable); 11637db96d56Sopenharmony_ci 11647db96d56Sopenharmony_ci // After the call to deduce_unreachable, the 'still_unreachable' set will 11657db96d56Sopenharmony_ci // have the PREV_MARK_COLLECTING set, but the objects are going to be 11667db96d56Sopenharmony_ci // removed so we can skip the expense of clearing the flag. 11677db96d56Sopenharmony_ci PyGC_Head* resurrected = unreachable; 11687db96d56Sopenharmony_ci deduce_unreachable(resurrected, still_unreachable); 11697db96d56Sopenharmony_ci clear_unreachable_mask(still_unreachable); 11707db96d56Sopenharmony_ci 11717db96d56Sopenharmony_ci // Move the resurrected objects to the old generation for future collection. 11727db96d56Sopenharmony_ci gc_list_merge(resurrected, old_generation); 11737db96d56Sopenharmony_ci} 11747db96d56Sopenharmony_ci 11757db96d56Sopenharmony_ci/* This is the main function. Read this to understand how the 11767db96d56Sopenharmony_ci * collection process works. */ 11777db96d56Sopenharmony_cistatic Py_ssize_t 11787db96d56Sopenharmony_cigc_collect_main(PyThreadState *tstate, int generation, 11797db96d56Sopenharmony_ci Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, 11807db96d56Sopenharmony_ci int nofail) 11817db96d56Sopenharmony_ci{ 11827db96d56Sopenharmony_ci int i; 11837db96d56Sopenharmony_ci Py_ssize_t m = 0; /* # objects collected */ 11847db96d56Sopenharmony_ci Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ 11857db96d56Sopenharmony_ci PyGC_Head *young; /* the generation we are examining */ 11867db96d56Sopenharmony_ci PyGC_Head *old; /* next older generation */ 11877db96d56Sopenharmony_ci PyGC_Head unreachable; /* non-problematic unreachable trash */ 11887db96d56Sopenharmony_ci PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ 11897db96d56Sopenharmony_ci PyGC_Head *gc; 11907db96d56Sopenharmony_ci _PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ 11917db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 11927db96d56Sopenharmony_ci 11937db96d56Sopenharmony_ci // gc_collect_main() must not be called before _PyGC_Init 11947db96d56Sopenharmony_ci // or after _PyGC_Fini() 11957db96d56Sopenharmony_ci assert(gcstate->garbage != NULL); 11967db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 11977db96d56Sopenharmony_ci 11987db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_STATS) { 11997db96d56Sopenharmony_ci PySys_WriteStderr("gc: collecting generation %d...\n", generation); 12007db96d56Sopenharmony_ci show_stats_each_generations(gcstate); 12017db96d56Sopenharmony_ci t1 = _PyTime_GetPerfCounter(); 12027db96d56Sopenharmony_ci } 12037db96d56Sopenharmony_ci 12047db96d56Sopenharmony_ci if (PyDTrace_GC_START_ENABLED()) 12057db96d56Sopenharmony_ci PyDTrace_GC_START(generation); 12067db96d56Sopenharmony_ci 12077db96d56Sopenharmony_ci /* update collection and allocation counters */ 12087db96d56Sopenharmony_ci if (generation+1 < NUM_GENERATIONS) 12097db96d56Sopenharmony_ci gcstate->generations[generation+1].count += 1; 12107db96d56Sopenharmony_ci for (i = 0; i <= generation; i++) 12117db96d56Sopenharmony_ci gcstate->generations[i].count = 0; 12127db96d56Sopenharmony_ci 12137db96d56Sopenharmony_ci /* merge younger generations with one we are currently collecting */ 12147db96d56Sopenharmony_ci for (i = 0; i < generation; i++) { 12157db96d56Sopenharmony_ci gc_list_merge(GEN_HEAD(gcstate, i), GEN_HEAD(gcstate, generation)); 12167db96d56Sopenharmony_ci } 12177db96d56Sopenharmony_ci 12187db96d56Sopenharmony_ci /* handy references */ 12197db96d56Sopenharmony_ci young = GEN_HEAD(gcstate, generation); 12207db96d56Sopenharmony_ci if (generation < NUM_GENERATIONS-1) 12217db96d56Sopenharmony_ci old = GEN_HEAD(gcstate, generation+1); 12227db96d56Sopenharmony_ci else 12237db96d56Sopenharmony_ci old = young; 12247db96d56Sopenharmony_ci validate_list(old, collecting_clear_unreachable_clear); 12257db96d56Sopenharmony_ci 12267db96d56Sopenharmony_ci deduce_unreachable(young, &unreachable); 12277db96d56Sopenharmony_ci 12287db96d56Sopenharmony_ci untrack_tuples(young); 12297db96d56Sopenharmony_ci /* Move reachable objects to next generation. */ 12307db96d56Sopenharmony_ci if (young != old) { 12317db96d56Sopenharmony_ci if (generation == NUM_GENERATIONS - 2) { 12327db96d56Sopenharmony_ci gcstate->long_lived_pending += gc_list_size(young); 12337db96d56Sopenharmony_ci } 12347db96d56Sopenharmony_ci gc_list_merge(young, old); 12357db96d56Sopenharmony_ci } 12367db96d56Sopenharmony_ci else { 12377db96d56Sopenharmony_ci /* We only un-track dicts in full collections, to avoid quadratic 12387db96d56Sopenharmony_ci dict build-up. See issue #14775. */ 12397db96d56Sopenharmony_ci untrack_dicts(young); 12407db96d56Sopenharmony_ci gcstate->long_lived_pending = 0; 12417db96d56Sopenharmony_ci gcstate->long_lived_total = gc_list_size(young); 12427db96d56Sopenharmony_ci } 12437db96d56Sopenharmony_ci 12447db96d56Sopenharmony_ci /* All objects in unreachable are trash, but objects reachable from 12457db96d56Sopenharmony_ci * legacy finalizers (e.g. tp_del) can't safely be deleted. 12467db96d56Sopenharmony_ci */ 12477db96d56Sopenharmony_ci gc_list_init(&finalizers); 12487db96d56Sopenharmony_ci // NEXT_MASK_UNREACHABLE is cleared here. 12497db96d56Sopenharmony_ci // After move_legacy_finalizers(), unreachable is normal list. 12507db96d56Sopenharmony_ci move_legacy_finalizers(&unreachable, &finalizers); 12517db96d56Sopenharmony_ci /* finalizers contains the unreachable objects with a legacy finalizer; 12527db96d56Sopenharmony_ci * unreachable objects reachable *from* those are also uncollectable, 12537db96d56Sopenharmony_ci * and we move those into the finalizers list too. 12547db96d56Sopenharmony_ci */ 12557db96d56Sopenharmony_ci move_legacy_finalizer_reachable(&finalizers); 12567db96d56Sopenharmony_ci 12577db96d56Sopenharmony_ci validate_list(&finalizers, collecting_clear_unreachable_clear); 12587db96d56Sopenharmony_ci validate_list(&unreachable, collecting_set_unreachable_clear); 12597db96d56Sopenharmony_ci 12607db96d56Sopenharmony_ci /* Print debugging information. */ 12617db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_COLLECTABLE) { 12627db96d56Sopenharmony_ci for (gc = GC_NEXT(&unreachable); gc != &unreachable; gc = GC_NEXT(gc)) { 12637db96d56Sopenharmony_ci debug_cycle("collectable", FROM_GC(gc)); 12647db96d56Sopenharmony_ci } 12657db96d56Sopenharmony_ci } 12667db96d56Sopenharmony_ci 12677db96d56Sopenharmony_ci /* Clear weakrefs and invoke callbacks as necessary. */ 12687db96d56Sopenharmony_ci m += handle_weakrefs(&unreachable, old); 12697db96d56Sopenharmony_ci 12707db96d56Sopenharmony_ci validate_list(old, collecting_clear_unreachable_clear); 12717db96d56Sopenharmony_ci validate_list(&unreachable, collecting_set_unreachable_clear); 12727db96d56Sopenharmony_ci 12737db96d56Sopenharmony_ci /* Call tp_finalize on objects which have one. */ 12747db96d56Sopenharmony_ci finalize_garbage(tstate, &unreachable); 12757db96d56Sopenharmony_ci 12767db96d56Sopenharmony_ci /* Handle any objects that may have resurrected after the call 12777db96d56Sopenharmony_ci * to 'finalize_garbage' and continue the collection with the 12787db96d56Sopenharmony_ci * objects that are still unreachable */ 12797db96d56Sopenharmony_ci PyGC_Head final_unreachable; 12807db96d56Sopenharmony_ci handle_resurrected_objects(&unreachable, &final_unreachable, old); 12817db96d56Sopenharmony_ci 12827db96d56Sopenharmony_ci /* Call tp_clear on objects in the final_unreachable set. This will cause 12837db96d56Sopenharmony_ci * the reference cycles to be broken. It may also cause some objects 12847db96d56Sopenharmony_ci * in finalizers to be freed. 12857db96d56Sopenharmony_ci */ 12867db96d56Sopenharmony_ci m += gc_list_size(&final_unreachable); 12877db96d56Sopenharmony_ci delete_garbage(tstate, gcstate, &final_unreachable, old); 12887db96d56Sopenharmony_ci 12897db96d56Sopenharmony_ci /* Collect statistics on uncollectable objects found and print 12907db96d56Sopenharmony_ci * debugging information. */ 12917db96d56Sopenharmony_ci for (gc = GC_NEXT(&finalizers); gc != &finalizers; gc = GC_NEXT(gc)) { 12927db96d56Sopenharmony_ci n++; 12937db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_UNCOLLECTABLE) 12947db96d56Sopenharmony_ci debug_cycle("uncollectable", FROM_GC(gc)); 12957db96d56Sopenharmony_ci } 12967db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_STATS) { 12977db96d56Sopenharmony_ci double d = _PyTime_AsSecondsDouble(_PyTime_GetPerfCounter() - t1); 12987db96d56Sopenharmony_ci PySys_WriteStderr( 12997db96d56Sopenharmony_ci "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n", 13007db96d56Sopenharmony_ci n+m, n, d); 13017db96d56Sopenharmony_ci } 13027db96d56Sopenharmony_ci 13037db96d56Sopenharmony_ci /* Append instances in the uncollectable set to a Python 13047db96d56Sopenharmony_ci * reachable list of garbage. The programmer has to deal with 13057db96d56Sopenharmony_ci * this if they insist on creating this type of structure. 13067db96d56Sopenharmony_ci */ 13077db96d56Sopenharmony_ci handle_legacy_finalizers(tstate, gcstate, &finalizers, old); 13087db96d56Sopenharmony_ci validate_list(old, collecting_clear_unreachable_clear); 13097db96d56Sopenharmony_ci 13107db96d56Sopenharmony_ci /* Clear free list only during the collection of the highest 13117db96d56Sopenharmony_ci * generation */ 13127db96d56Sopenharmony_ci if (generation == NUM_GENERATIONS-1) { 13137db96d56Sopenharmony_ci clear_freelists(tstate->interp); 13147db96d56Sopenharmony_ci } 13157db96d56Sopenharmony_ci 13167db96d56Sopenharmony_ci if (_PyErr_Occurred(tstate)) { 13177db96d56Sopenharmony_ci if (nofail) { 13187db96d56Sopenharmony_ci _PyErr_Clear(tstate); 13197db96d56Sopenharmony_ci } 13207db96d56Sopenharmony_ci else { 13217db96d56Sopenharmony_ci _PyErr_WriteUnraisableMsg("in garbage collection", NULL); 13227db96d56Sopenharmony_ci } 13237db96d56Sopenharmony_ci } 13247db96d56Sopenharmony_ci 13257db96d56Sopenharmony_ci /* Update stats */ 13267db96d56Sopenharmony_ci if (n_collected) { 13277db96d56Sopenharmony_ci *n_collected = m; 13287db96d56Sopenharmony_ci } 13297db96d56Sopenharmony_ci if (n_uncollectable) { 13307db96d56Sopenharmony_ci *n_uncollectable = n; 13317db96d56Sopenharmony_ci } 13327db96d56Sopenharmony_ci 13337db96d56Sopenharmony_ci struct gc_generation_stats *stats = &gcstate->generation_stats[generation]; 13347db96d56Sopenharmony_ci stats->collections++; 13357db96d56Sopenharmony_ci stats->collected += m; 13367db96d56Sopenharmony_ci stats->uncollectable += n; 13377db96d56Sopenharmony_ci 13387db96d56Sopenharmony_ci if (PyDTrace_GC_DONE_ENABLED()) { 13397db96d56Sopenharmony_ci PyDTrace_GC_DONE(n + m); 13407db96d56Sopenharmony_ci } 13417db96d56Sopenharmony_ci 13427db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 13437db96d56Sopenharmony_ci return n + m; 13447db96d56Sopenharmony_ci} 13457db96d56Sopenharmony_ci 13467db96d56Sopenharmony_ci/* Invoke progress callbacks to notify clients that garbage collection 13477db96d56Sopenharmony_ci * is starting or stopping 13487db96d56Sopenharmony_ci */ 13497db96d56Sopenharmony_cistatic void 13507db96d56Sopenharmony_ciinvoke_gc_callback(PyThreadState *tstate, const char *phase, 13517db96d56Sopenharmony_ci int generation, Py_ssize_t collected, 13527db96d56Sopenharmony_ci Py_ssize_t uncollectable) 13537db96d56Sopenharmony_ci{ 13547db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 13557db96d56Sopenharmony_ci 13567db96d56Sopenharmony_ci /* we may get called very early */ 13577db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 13587db96d56Sopenharmony_ci if (gcstate->callbacks == NULL) { 13597db96d56Sopenharmony_ci return; 13607db96d56Sopenharmony_ci } 13617db96d56Sopenharmony_ci 13627db96d56Sopenharmony_ci /* The local variable cannot be rebound, check it for sanity */ 13637db96d56Sopenharmony_ci assert(PyList_CheckExact(gcstate->callbacks)); 13647db96d56Sopenharmony_ci PyObject *info = NULL; 13657db96d56Sopenharmony_ci if (PyList_GET_SIZE(gcstate->callbacks) != 0) { 13667db96d56Sopenharmony_ci info = Py_BuildValue("{sisnsn}", 13677db96d56Sopenharmony_ci "generation", generation, 13687db96d56Sopenharmony_ci "collected", collected, 13697db96d56Sopenharmony_ci "uncollectable", uncollectable); 13707db96d56Sopenharmony_ci if (info == NULL) { 13717db96d56Sopenharmony_ci PyErr_WriteUnraisable(NULL); 13727db96d56Sopenharmony_ci return; 13737db96d56Sopenharmony_ci } 13747db96d56Sopenharmony_ci } 13757db96d56Sopenharmony_ci for (Py_ssize_t i=0; i<PyList_GET_SIZE(gcstate->callbacks); i++) { 13767db96d56Sopenharmony_ci PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i); 13777db96d56Sopenharmony_ci Py_INCREF(cb); /* make sure cb doesn't go away */ 13787db96d56Sopenharmony_ci r = PyObject_CallFunction(cb, "sO", phase, info); 13797db96d56Sopenharmony_ci if (r == NULL) { 13807db96d56Sopenharmony_ci PyErr_WriteUnraisable(cb); 13817db96d56Sopenharmony_ci } 13827db96d56Sopenharmony_ci else { 13837db96d56Sopenharmony_ci Py_DECREF(r); 13847db96d56Sopenharmony_ci } 13857db96d56Sopenharmony_ci Py_DECREF(cb); 13867db96d56Sopenharmony_ci } 13877db96d56Sopenharmony_ci Py_XDECREF(info); 13887db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 13897db96d56Sopenharmony_ci} 13907db96d56Sopenharmony_ci 13917db96d56Sopenharmony_ci/* Perform garbage collection of a generation and invoke 13927db96d56Sopenharmony_ci * progress callbacks. 13937db96d56Sopenharmony_ci */ 13947db96d56Sopenharmony_cistatic Py_ssize_t 13957db96d56Sopenharmony_cigc_collect_with_callback(PyThreadState *tstate, int generation) 13967db96d56Sopenharmony_ci{ 13977db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 13987db96d56Sopenharmony_ci Py_ssize_t result, collected, uncollectable; 13997db96d56Sopenharmony_ci invoke_gc_callback(tstate, "start", generation, 0, 0); 14007db96d56Sopenharmony_ci result = gc_collect_main(tstate, generation, &collected, &uncollectable, 0); 14017db96d56Sopenharmony_ci invoke_gc_callback(tstate, "stop", generation, collected, uncollectable); 14027db96d56Sopenharmony_ci assert(!_PyErr_Occurred(tstate)); 14037db96d56Sopenharmony_ci return result; 14047db96d56Sopenharmony_ci} 14057db96d56Sopenharmony_ci 14067db96d56Sopenharmony_cistatic Py_ssize_t 14077db96d56Sopenharmony_cigc_collect_generations(PyThreadState *tstate) 14087db96d56Sopenharmony_ci{ 14097db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 14107db96d56Sopenharmony_ci /* Find the oldest generation (highest numbered) where the count 14117db96d56Sopenharmony_ci * exceeds the threshold. Objects in the that generation and 14127db96d56Sopenharmony_ci * generations younger than it will be collected. */ 14137db96d56Sopenharmony_ci Py_ssize_t n = 0; 14147db96d56Sopenharmony_ci for (int i = NUM_GENERATIONS-1; i >= 0; i--) { 14157db96d56Sopenharmony_ci if (gcstate->generations[i].count > gcstate->generations[i].threshold) { 14167db96d56Sopenharmony_ci /* Avoid quadratic performance degradation in number 14177db96d56Sopenharmony_ci of tracked objects (see also issue #4074): 14187db96d56Sopenharmony_ci 14197db96d56Sopenharmony_ci To limit the cost of garbage collection, there are two strategies; 14207db96d56Sopenharmony_ci - make each collection faster, e.g. by scanning fewer objects 14217db96d56Sopenharmony_ci - do less collections 14227db96d56Sopenharmony_ci This heuristic is about the latter strategy. 14237db96d56Sopenharmony_ci 14247db96d56Sopenharmony_ci In addition to the various configurable thresholds, we only trigger a 14257db96d56Sopenharmony_ci full collection if the ratio 14267db96d56Sopenharmony_ci 14277db96d56Sopenharmony_ci long_lived_pending / long_lived_total 14287db96d56Sopenharmony_ci 14297db96d56Sopenharmony_ci is above a given value (hardwired to 25%). 14307db96d56Sopenharmony_ci 14317db96d56Sopenharmony_ci The reason is that, while "non-full" collections (i.e., collections of 14327db96d56Sopenharmony_ci the young and middle generations) will always examine roughly the same 14337db96d56Sopenharmony_ci number of objects -- determined by the aforementioned thresholds --, 14347db96d56Sopenharmony_ci the cost of a full collection is proportional to the total number of 14357db96d56Sopenharmony_ci long-lived objects, which is virtually unbounded. 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci Indeed, it has been remarked that doing a full collection every 14387db96d56Sopenharmony_ci <constant number> of object creations entails a dramatic performance 14397db96d56Sopenharmony_ci degradation in workloads which consist in creating and storing lots of 14407db96d56Sopenharmony_ci long-lived objects (e.g. building a large list of GC-tracked objects would 14417db96d56Sopenharmony_ci show quadratic performance, instead of linear as expected: see issue #4074). 14427db96d56Sopenharmony_ci 14437db96d56Sopenharmony_ci Using the above ratio, instead, yields amortized linear performance in 14447db96d56Sopenharmony_ci the total number of objects (the effect of which can be summarized 14457db96d56Sopenharmony_ci thusly: "each full garbage collection is more and more costly as the 14467db96d56Sopenharmony_ci number of objects grows, but we do fewer and fewer of them"). 14477db96d56Sopenharmony_ci 14487db96d56Sopenharmony_ci This heuristic was suggested by Martin von Löwis on python-dev in 14497db96d56Sopenharmony_ci June 2008. His original analysis and proposal can be found at: 14507db96d56Sopenharmony_ci http://mail.python.org/pipermail/python-dev/2008-June/080579.html 14517db96d56Sopenharmony_ci */ 14527db96d56Sopenharmony_ci if (i == NUM_GENERATIONS - 1 14537db96d56Sopenharmony_ci && gcstate->long_lived_pending < gcstate->long_lived_total / 4) 14547db96d56Sopenharmony_ci continue; 14557db96d56Sopenharmony_ci n = gc_collect_with_callback(tstate, i); 14567db96d56Sopenharmony_ci break; 14577db96d56Sopenharmony_ci } 14587db96d56Sopenharmony_ci } 14597db96d56Sopenharmony_ci return n; 14607db96d56Sopenharmony_ci} 14617db96d56Sopenharmony_ci 14627db96d56Sopenharmony_ci#include "clinic/gcmodule.c.h" 14637db96d56Sopenharmony_ci 14647db96d56Sopenharmony_ci/*[clinic input] 14657db96d56Sopenharmony_cigc.enable 14667db96d56Sopenharmony_ci 14677db96d56Sopenharmony_ciEnable automatic garbage collection. 14687db96d56Sopenharmony_ci[clinic start generated code]*/ 14697db96d56Sopenharmony_ci 14707db96d56Sopenharmony_cistatic PyObject * 14717db96d56Sopenharmony_cigc_enable_impl(PyObject *module) 14727db96d56Sopenharmony_ci/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/ 14737db96d56Sopenharmony_ci{ 14747db96d56Sopenharmony_ci PyGC_Enable(); 14757db96d56Sopenharmony_ci Py_RETURN_NONE; 14767db96d56Sopenharmony_ci} 14777db96d56Sopenharmony_ci 14787db96d56Sopenharmony_ci/*[clinic input] 14797db96d56Sopenharmony_cigc.disable 14807db96d56Sopenharmony_ci 14817db96d56Sopenharmony_ciDisable automatic garbage collection. 14827db96d56Sopenharmony_ci[clinic start generated code]*/ 14837db96d56Sopenharmony_ci 14847db96d56Sopenharmony_cistatic PyObject * 14857db96d56Sopenharmony_cigc_disable_impl(PyObject *module) 14867db96d56Sopenharmony_ci/*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/ 14877db96d56Sopenharmony_ci{ 14887db96d56Sopenharmony_ci PyGC_Disable(); 14897db96d56Sopenharmony_ci Py_RETURN_NONE; 14907db96d56Sopenharmony_ci} 14917db96d56Sopenharmony_ci 14927db96d56Sopenharmony_ci/*[clinic input] 14937db96d56Sopenharmony_cigc.isenabled -> bool 14947db96d56Sopenharmony_ci 14957db96d56Sopenharmony_ciReturns true if automatic garbage collection is enabled. 14967db96d56Sopenharmony_ci[clinic start generated code]*/ 14977db96d56Sopenharmony_ci 14987db96d56Sopenharmony_cistatic int 14997db96d56Sopenharmony_cigc_isenabled_impl(PyObject *module) 15007db96d56Sopenharmony_ci/*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/ 15017db96d56Sopenharmony_ci{ 15027db96d56Sopenharmony_ci return PyGC_IsEnabled(); 15037db96d56Sopenharmony_ci} 15047db96d56Sopenharmony_ci 15057db96d56Sopenharmony_ci/*[clinic input] 15067db96d56Sopenharmony_cigc.collect -> Py_ssize_t 15077db96d56Sopenharmony_ci 15087db96d56Sopenharmony_ci generation: int(c_default="NUM_GENERATIONS - 1") = 2 15097db96d56Sopenharmony_ci 15107db96d56Sopenharmony_ciRun the garbage collector. 15117db96d56Sopenharmony_ci 15127db96d56Sopenharmony_ciWith no arguments, run a full collection. The optional argument 15137db96d56Sopenharmony_cimay be an integer specifying which generation to collect. A ValueError 15147db96d56Sopenharmony_ciis raised if the generation number is invalid. 15157db96d56Sopenharmony_ci 15167db96d56Sopenharmony_ciThe number of unreachable objects is returned. 15177db96d56Sopenharmony_ci[clinic start generated code]*/ 15187db96d56Sopenharmony_ci 15197db96d56Sopenharmony_cistatic Py_ssize_t 15207db96d56Sopenharmony_cigc_collect_impl(PyObject *module, int generation) 15217db96d56Sopenharmony_ci/*[clinic end generated code: output=b697e633043233c7 input=40720128b682d879]*/ 15227db96d56Sopenharmony_ci{ 15237db96d56Sopenharmony_ci PyThreadState *tstate = _PyThreadState_GET(); 15247db96d56Sopenharmony_ci 15257db96d56Sopenharmony_ci if (generation < 0 || generation >= NUM_GENERATIONS) { 15267db96d56Sopenharmony_ci _PyErr_SetString(tstate, PyExc_ValueError, "invalid generation"); 15277db96d56Sopenharmony_ci return -1; 15287db96d56Sopenharmony_ci } 15297db96d56Sopenharmony_ci 15307db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 15317db96d56Sopenharmony_ci Py_ssize_t n; 15327db96d56Sopenharmony_ci if (gcstate->collecting) { 15337db96d56Sopenharmony_ci /* already collecting, don't do anything */ 15347db96d56Sopenharmony_ci n = 0; 15357db96d56Sopenharmony_ci } 15367db96d56Sopenharmony_ci else { 15377db96d56Sopenharmony_ci gcstate->collecting = 1; 15387db96d56Sopenharmony_ci n = gc_collect_with_callback(tstate, generation); 15397db96d56Sopenharmony_ci gcstate->collecting = 0; 15407db96d56Sopenharmony_ci } 15417db96d56Sopenharmony_ci return n; 15427db96d56Sopenharmony_ci} 15437db96d56Sopenharmony_ci 15447db96d56Sopenharmony_ci/*[clinic input] 15457db96d56Sopenharmony_cigc.set_debug 15467db96d56Sopenharmony_ci 15477db96d56Sopenharmony_ci flags: int 15487db96d56Sopenharmony_ci An integer that can have the following bits turned on: 15497db96d56Sopenharmony_ci DEBUG_STATS - Print statistics during collection. 15507db96d56Sopenharmony_ci DEBUG_COLLECTABLE - Print collectable objects found. 15517db96d56Sopenharmony_ci DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects 15527db96d56Sopenharmony_ci found. 15537db96d56Sopenharmony_ci DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them. 15547db96d56Sopenharmony_ci DEBUG_LEAK - Debug leaking programs (everything but STATS). 15557db96d56Sopenharmony_ci / 15567db96d56Sopenharmony_ci 15577db96d56Sopenharmony_ciSet the garbage collection debugging flags. 15587db96d56Sopenharmony_ci 15597db96d56Sopenharmony_ciDebugging information is written to sys.stderr. 15607db96d56Sopenharmony_ci[clinic start generated code]*/ 15617db96d56Sopenharmony_ci 15627db96d56Sopenharmony_cistatic PyObject * 15637db96d56Sopenharmony_cigc_set_debug_impl(PyObject *module, int flags) 15647db96d56Sopenharmony_ci/*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/ 15657db96d56Sopenharmony_ci{ 15667db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 15677db96d56Sopenharmony_ci gcstate->debug = flags; 15687db96d56Sopenharmony_ci Py_RETURN_NONE; 15697db96d56Sopenharmony_ci} 15707db96d56Sopenharmony_ci 15717db96d56Sopenharmony_ci/*[clinic input] 15727db96d56Sopenharmony_cigc.get_debug -> int 15737db96d56Sopenharmony_ci 15747db96d56Sopenharmony_ciGet the garbage collection debugging flags. 15757db96d56Sopenharmony_ci[clinic start generated code]*/ 15767db96d56Sopenharmony_ci 15777db96d56Sopenharmony_cistatic int 15787db96d56Sopenharmony_cigc_get_debug_impl(PyObject *module) 15797db96d56Sopenharmony_ci/*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/ 15807db96d56Sopenharmony_ci{ 15817db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 15827db96d56Sopenharmony_ci return gcstate->debug; 15837db96d56Sopenharmony_ci} 15847db96d56Sopenharmony_ci 15857db96d56Sopenharmony_ciPyDoc_STRVAR(gc_set_thresh__doc__, 15867db96d56Sopenharmony_ci"set_threshold(threshold0, [threshold1, threshold2]) -> None\n" 15877db96d56Sopenharmony_ci"\n" 15887db96d56Sopenharmony_ci"Sets the collection thresholds. Setting threshold0 to zero disables\n" 15897db96d56Sopenharmony_ci"collection.\n"); 15907db96d56Sopenharmony_ci 15917db96d56Sopenharmony_cistatic PyObject * 15927db96d56Sopenharmony_cigc_set_threshold(PyObject *self, PyObject *args) 15937db96d56Sopenharmony_ci{ 15947db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 15957db96d56Sopenharmony_ci if (!PyArg_ParseTuple(args, "i|ii:set_threshold", 15967db96d56Sopenharmony_ci &gcstate->generations[0].threshold, 15977db96d56Sopenharmony_ci &gcstate->generations[1].threshold, 15987db96d56Sopenharmony_ci &gcstate->generations[2].threshold)) 15997db96d56Sopenharmony_ci return NULL; 16007db96d56Sopenharmony_ci for (int i = 3; i < NUM_GENERATIONS; i++) { 16017db96d56Sopenharmony_ci /* generations higher than 2 get the same threshold */ 16027db96d56Sopenharmony_ci gcstate->generations[i].threshold = gcstate->generations[2].threshold; 16037db96d56Sopenharmony_ci } 16047db96d56Sopenharmony_ci Py_RETURN_NONE; 16057db96d56Sopenharmony_ci} 16067db96d56Sopenharmony_ci 16077db96d56Sopenharmony_ci/*[clinic input] 16087db96d56Sopenharmony_cigc.get_threshold 16097db96d56Sopenharmony_ci 16107db96d56Sopenharmony_ciReturn the current collection thresholds. 16117db96d56Sopenharmony_ci[clinic start generated code]*/ 16127db96d56Sopenharmony_ci 16137db96d56Sopenharmony_cistatic PyObject * 16147db96d56Sopenharmony_cigc_get_threshold_impl(PyObject *module) 16157db96d56Sopenharmony_ci/*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/ 16167db96d56Sopenharmony_ci{ 16177db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 16187db96d56Sopenharmony_ci return Py_BuildValue("(iii)", 16197db96d56Sopenharmony_ci gcstate->generations[0].threshold, 16207db96d56Sopenharmony_ci gcstate->generations[1].threshold, 16217db96d56Sopenharmony_ci gcstate->generations[2].threshold); 16227db96d56Sopenharmony_ci} 16237db96d56Sopenharmony_ci 16247db96d56Sopenharmony_ci/*[clinic input] 16257db96d56Sopenharmony_cigc.get_count 16267db96d56Sopenharmony_ci 16277db96d56Sopenharmony_ciReturn a three-tuple of the current collection counts. 16287db96d56Sopenharmony_ci[clinic start generated code]*/ 16297db96d56Sopenharmony_ci 16307db96d56Sopenharmony_cistatic PyObject * 16317db96d56Sopenharmony_cigc_get_count_impl(PyObject *module) 16327db96d56Sopenharmony_ci/*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/ 16337db96d56Sopenharmony_ci{ 16347db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 16357db96d56Sopenharmony_ci return Py_BuildValue("(iii)", 16367db96d56Sopenharmony_ci gcstate->generations[0].count, 16377db96d56Sopenharmony_ci gcstate->generations[1].count, 16387db96d56Sopenharmony_ci gcstate->generations[2].count); 16397db96d56Sopenharmony_ci} 16407db96d56Sopenharmony_ci 16417db96d56Sopenharmony_cistatic int 16427db96d56Sopenharmony_cireferrersvisit(PyObject* obj, PyObject *objs) 16437db96d56Sopenharmony_ci{ 16447db96d56Sopenharmony_ci Py_ssize_t i; 16457db96d56Sopenharmony_ci for (i = 0; i < PyTuple_GET_SIZE(objs); i++) 16467db96d56Sopenharmony_ci if (PyTuple_GET_ITEM(objs, i) == obj) 16477db96d56Sopenharmony_ci return 1; 16487db96d56Sopenharmony_ci return 0; 16497db96d56Sopenharmony_ci} 16507db96d56Sopenharmony_ci 16517db96d56Sopenharmony_cistatic int 16527db96d56Sopenharmony_cigc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist) 16537db96d56Sopenharmony_ci{ 16547db96d56Sopenharmony_ci PyGC_Head *gc; 16557db96d56Sopenharmony_ci PyObject *obj; 16567db96d56Sopenharmony_ci traverseproc traverse; 16577db96d56Sopenharmony_ci for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) { 16587db96d56Sopenharmony_ci obj = FROM_GC(gc); 16597db96d56Sopenharmony_ci traverse = Py_TYPE(obj)->tp_traverse; 16607db96d56Sopenharmony_ci if (obj == objs || obj == resultlist) 16617db96d56Sopenharmony_ci continue; 16627db96d56Sopenharmony_ci if (traverse(obj, (visitproc)referrersvisit, objs)) { 16637db96d56Sopenharmony_ci if (PyList_Append(resultlist, obj) < 0) 16647db96d56Sopenharmony_ci return 0; /* error */ 16657db96d56Sopenharmony_ci } 16667db96d56Sopenharmony_ci } 16677db96d56Sopenharmony_ci return 1; /* no error */ 16687db96d56Sopenharmony_ci} 16697db96d56Sopenharmony_ci 16707db96d56Sopenharmony_ciPyDoc_STRVAR(gc_get_referrers__doc__, 16717db96d56Sopenharmony_ci"get_referrers(*objs) -> list\n\ 16727db96d56Sopenharmony_ciReturn the list of objects that directly refer to any of objs."); 16737db96d56Sopenharmony_ci 16747db96d56Sopenharmony_cistatic PyObject * 16757db96d56Sopenharmony_cigc_get_referrers(PyObject *self, PyObject *args) 16767db96d56Sopenharmony_ci{ 16777db96d56Sopenharmony_ci if (PySys_Audit("gc.get_referrers", "(O)", args) < 0) { 16787db96d56Sopenharmony_ci return NULL; 16797db96d56Sopenharmony_ci } 16807db96d56Sopenharmony_ci 16817db96d56Sopenharmony_ci PyObject *result = PyList_New(0); 16827db96d56Sopenharmony_ci if (!result) { 16837db96d56Sopenharmony_ci return NULL; 16847db96d56Sopenharmony_ci } 16857db96d56Sopenharmony_ci 16867db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 16877db96d56Sopenharmony_ci for (int i = 0; i < NUM_GENERATIONS; i++) { 16887db96d56Sopenharmony_ci if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) { 16897db96d56Sopenharmony_ci Py_DECREF(result); 16907db96d56Sopenharmony_ci return NULL; 16917db96d56Sopenharmony_ci } 16927db96d56Sopenharmony_ci } 16937db96d56Sopenharmony_ci return result; 16947db96d56Sopenharmony_ci} 16957db96d56Sopenharmony_ci 16967db96d56Sopenharmony_ci/* Append obj to list; return true if error (out of memory), false if OK. */ 16977db96d56Sopenharmony_cistatic int 16987db96d56Sopenharmony_cireferentsvisit(PyObject *obj, PyObject *list) 16997db96d56Sopenharmony_ci{ 17007db96d56Sopenharmony_ci return PyList_Append(list, obj) < 0; 17017db96d56Sopenharmony_ci} 17027db96d56Sopenharmony_ci 17037db96d56Sopenharmony_ciPyDoc_STRVAR(gc_get_referents__doc__, 17047db96d56Sopenharmony_ci"get_referents(*objs) -> list\n\ 17057db96d56Sopenharmony_ciReturn the list of objects that are directly referred to by objs."); 17067db96d56Sopenharmony_ci 17077db96d56Sopenharmony_cistatic PyObject * 17087db96d56Sopenharmony_cigc_get_referents(PyObject *self, PyObject *args) 17097db96d56Sopenharmony_ci{ 17107db96d56Sopenharmony_ci Py_ssize_t i; 17117db96d56Sopenharmony_ci if (PySys_Audit("gc.get_referents", "(O)", args) < 0) { 17127db96d56Sopenharmony_ci return NULL; 17137db96d56Sopenharmony_ci } 17147db96d56Sopenharmony_ci PyObject *result = PyList_New(0); 17157db96d56Sopenharmony_ci 17167db96d56Sopenharmony_ci if (result == NULL) 17177db96d56Sopenharmony_ci return NULL; 17187db96d56Sopenharmony_ci 17197db96d56Sopenharmony_ci for (i = 0; i < PyTuple_GET_SIZE(args); i++) { 17207db96d56Sopenharmony_ci traverseproc traverse; 17217db96d56Sopenharmony_ci PyObject *obj = PyTuple_GET_ITEM(args, i); 17227db96d56Sopenharmony_ci 17237db96d56Sopenharmony_ci if (!_PyObject_IS_GC(obj)) 17247db96d56Sopenharmony_ci continue; 17257db96d56Sopenharmony_ci traverse = Py_TYPE(obj)->tp_traverse; 17267db96d56Sopenharmony_ci if (! traverse) 17277db96d56Sopenharmony_ci continue; 17287db96d56Sopenharmony_ci if (traverse(obj, (visitproc)referentsvisit, result)) { 17297db96d56Sopenharmony_ci Py_DECREF(result); 17307db96d56Sopenharmony_ci return NULL; 17317db96d56Sopenharmony_ci } 17327db96d56Sopenharmony_ci } 17337db96d56Sopenharmony_ci return result; 17347db96d56Sopenharmony_ci} 17357db96d56Sopenharmony_ci 17367db96d56Sopenharmony_ci/*[clinic input] 17377db96d56Sopenharmony_cigc.get_objects 17387db96d56Sopenharmony_ci generation: Py_ssize_t(accept={int, NoneType}, c_default="-1") = None 17397db96d56Sopenharmony_ci Generation to extract the objects from. 17407db96d56Sopenharmony_ci 17417db96d56Sopenharmony_ciReturn a list of objects tracked by the collector (excluding the list returned). 17427db96d56Sopenharmony_ci 17437db96d56Sopenharmony_ciIf generation is not None, return only the objects tracked by the collector 17447db96d56Sopenharmony_cithat are in that generation. 17457db96d56Sopenharmony_ci[clinic start generated code]*/ 17467db96d56Sopenharmony_ci 17477db96d56Sopenharmony_cistatic PyObject * 17487db96d56Sopenharmony_cigc_get_objects_impl(PyObject *module, Py_ssize_t generation) 17497db96d56Sopenharmony_ci/*[clinic end generated code: output=48b35fea4ba6cb0e input=ef7da9df9806754c]*/ 17507db96d56Sopenharmony_ci{ 17517db96d56Sopenharmony_ci PyThreadState *tstate = _PyThreadState_GET(); 17527db96d56Sopenharmony_ci int i; 17537db96d56Sopenharmony_ci PyObject* result; 17547db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 17557db96d56Sopenharmony_ci 17567db96d56Sopenharmony_ci if (PySys_Audit("gc.get_objects", "n", generation) < 0) { 17577db96d56Sopenharmony_ci return NULL; 17587db96d56Sopenharmony_ci } 17597db96d56Sopenharmony_ci 17607db96d56Sopenharmony_ci result = PyList_New(0); 17617db96d56Sopenharmony_ci if (result == NULL) { 17627db96d56Sopenharmony_ci return NULL; 17637db96d56Sopenharmony_ci } 17647db96d56Sopenharmony_ci 17657db96d56Sopenharmony_ci /* If generation is passed, we extract only that generation */ 17667db96d56Sopenharmony_ci if (generation != -1) { 17677db96d56Sopenharmony_ci if (generation >= NUM_GENERATIONS) { 17687db96d56Sopenharmony_ci _PyErr_Format(tstate, PyExc_ValueError, 17697db96d56Sopenharmony_ci "generation parameter must be less than the number of " 17707db96d56Sopenharmony_ci "available generations (%i)", 17717db96d56Sopenharmony_ci NUM_GENERATIONS); 17727db96d56Sopenharmony_ci goto error; 17737db96d56Sopenharmony_ci } 17747db96d56Sopenharmony_ci 17757db96d56Sopenharmony_ci if (generation < 0) { 17767db96d56Sopenharmony_ci _PyErr_SetString(tstate, PyExc_ValueError, 17777db96d56Sopenharmony_ci "generation parameter cannot be negative"); 17787db96d56Sopenharmony_ci goto error; 17797db96d56Sopenharmony_ci } 17807db96d56Sopenharmony_ci 17817db96d56Sopenharmony_ci if (append_objects(result, GEN_HEAD(gcstate, generation))) { 17827db96d56Sopenharmony_ci goto error; 17837db96d56Sopenharmony_ci } 17847db96d56Sopenharmony_ci 17857db96d56Sopenharmony_ci return result; 17867db96d56Sopenharmony_ci } 17877db96d56Sopenharmony_ci 17887db96d56Sopenharmony_ci /* If generation is not passed or None, get all objects from all generations */ 17897db96d56Sopenharmony_ci for (i = 0; i < NUM_GENERATIONS; i++) { 17907db96d56Sopenharmony_ci if (append_objects(result, GEN_HEAD(gcstate, i))) { 17917db96d56Sopenharmony_ci goto error; 17927db96d56Sopenharmony_ci } 17937db96d56Sopenharmony_ci } 17947db96d56Sopenharmony_ci return result; 17957db96d56Sopenharmony_ci 17967db96d56Sopenharmony_cierror: 17977db96d56Sopenharmony_ci Py_DECREF(result); 17987db96d56Sopenharmony_ci return NULL; 17997db96d56Sopenharmony_ci} 18007db96d56Sopenharmony_ci 18017db96d56Sopenharmony_ci/*[clinic input] 18027db96d56Sopenharmony_cigc.get_stats 18037db96d56Sopenharmony_ci 18047db96d56Sopenharmony_ciReturn a list of dictionaries containing per-generation statistics. 18057db96d56Sopenharmony_ci[clinic start generated code]*/ 18067db96d56Sopenharmony_ci 18077db96d56Sopenharmony_cistatic PyObject * 18087db96d56Sopenharmony_cigc_get_stats_impl(PyObject *module) 18097db96d56Sopenharmony_ci/*[clinic end generated code: output=a8ab1d8a5d26f3ab input=1ef4ed9d17b1a470]*/ 18107db96d56Sopenharmony_ci{ 18117db96d56Sopenharmony_ci int i; 18127db96d56Sopenharmony_ci struct gc_generation_stats stats[NUM_GENERATIONS], *st; 18137db96d56Sopenharmony_ci 18147db96d56Sopenharmony_ci /* To get consistent values despite allocations while constructing 18157db96d56Sopenharmony_ci the result list, we use a snapshot of the running stats. */ 18167db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 18177db96d56Sopenharmony_ci for (i = 0; i < NUM_GENERATIONS; i++) { 18187db96d56Sopenharmony_ci stats[i] = gcstate->generation_stats[i]; 18197db96d56Sopenharmony_ci } 18207db96d56Sopenharmony_ci 18217db96d56Sopenharmony_ci PyObject *result = PyList_New(0); 18227db96d56Sopenharmony_ci if (result == NULL) 18237db96d56Sopenharmony_ci return NULL; 18247db96d56Sopenharmony_ci 18257db96d56Sopenharmony_ci for (i = 0; i < NUM_GENERATIONS; i++) { 18267db96d56Sopenharmony_ci PyObject *dict; 18277db96d56Sopenharmony_ci st = &stats[i]; 18287db96d56Sopenharmony_ci dict = Py_BuildValue("{snsnsn}", 18297db96d56Sopenharmony_ci "collections", st->collections, 18307db96d56Sopenharmony_ci "collected", st->collected, 18317db96d56Sopenharmony_ci "uncollectable", st->uncollectable 18327db96d56Sopenharmony_ci ); 18337db96d56Sopenharmony_ci if (dict == NULL) 18347db96d56Sopenharmony_ci goto error; 18357db96d56Sopenharmony_ci if (PyList_Append(result, dict)) { 18367db96d56Sopenharmony_ci Py_DECREF(dict); 18377db96d56Sopenharmony_ci goto error; 18387db96d56Sopenharmony_ci } 18397db96d56Sopenharmony_ci Py_DECREF(dict); 18407db96d56Sopenharmony_ci } 18417db96d56Sopenharmony_ci return result; 18427db96d56Sopenharmony_ci 18437db96d56Sopenharmony_cierror: 18447db96d56Sopenharmony_ci Py_XDECREF(result); 18457db96d56Sopenharmony_ci return NULL; 18467db96d56Sopenharmony_ci} 18477db96d56Sopenharmony_ci 18487db96d56Sopenharmony_ci 18497db96d56Sopenharmony_ci/*[clinic input] 18507db96d56Sopenharmony_cigc.is_tracked 18517db96d56Sopenharmony_ci 18527db96d56Sopenharmony_ci obj: object 18537db96d56Sopenharmony_ci / 18547db96d56Sopenharmony_ci 18557db96d56Sopenharmony_ciReturns true if the object is tracked by the garbage collector. 18567db96d56Sopenharmony_ci 18577db96d56Sopenharmony_ciSimple atomic objects will return false. 18587db96d56Sopenharmony_ci[clinic start generated code]*/ 18597db96d56Sopenharmony_ci 18607db96d56Sopenharmony_cistatic PyObject * 18617db96d56Sopenharmony_cigc_is_tracked(PyObject *module, PyObject *obj) 18627db96d56Sopenharmony_ci/*[clinic end generated code: output=14f0103423b28e31 input=d83057f170ea2723]*/ 18637db96d56Sopenharmony_ci{ 18647db96d56Sopenharmony_ci PyObject *result; 18657db96d56Sopenharmony_ci 18667db96d56Sopenharmony_ci if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) 18677db96d56Sopenharmony_ci result = Py_True; 18687db96d56Sopenharmony_ci else 18697db96d56Sopenharmony_ci result = Py_False; 18707db96d56Sopenharmony_ci Py_INCREF(result); 18717db96d56Sopenharmony_ci return result; 18727db96d56Sopenharmony_ci} 18737db96d56Sopenharmony_ci 18747db96d56Sopenharmony_ci/*[clinic input] 18757db96d56Sopenharmony_cigc.is_finalized 18767db96d56Sopenharmony_ci 18777db96d56Sopenharmony_ci obj: object 18787db96d56Sopenharmony_ci / 18797db96d56Sopenharmony_ci 18807db96d56Sopenharmony_ciReturns true if the object has been already finalized by the GC. 18817db96d56Sopenharmony_ci[clinic start generated code]*/ 18827db96d56Sopenharmony_ci 18837db96d56Sopenharmony_cistatic PyObject * 18847db96d56Sopenharmony_cigc_is_finalized(PyObject *module, PyObject *obj) 18857db96d56Sopenharmony_ci/*[clinic end generated code: output=e1516ac119a918ed input=201d0c58f69ae390]*/ 18867db96d56Sopenharmony_ci{ 18877db96d56Sopenharmony_ci if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { 18887db96d56Sopenharmony_ci Py_RETURN_TRUE; 18897db96d56Sopenharmony_ci } 18907db96d56Sopenharmony_ci Py_RETURN_FALSE; 18917db96d56Sopenharmony_ci} 18927db96d56Sopenharmony_ci 18937db96d56Sopenharmony_ci/*[clinic input] 18947db96d56Sopenharmony_cigc.freeze 18957db96d56Sopenharmony_ci 18967db96d56Sopenharmony_ciFreeze all current tracked objects and ignore them for future collections. 18977db96d56Sopenharmony_ci 18987db96d56Sopenharmony_ciThis can be used before a POSIX fork() call to make the gc copy-on-write friendly. 18997db96d56Sopenharmony_ciNote: collection before a POSIX fork() call may free pages for future allocation 19007db96d56Sopenharmony_ciwhich can cause copy-on-write. 19017db96d56Sopenharmony_ci[clinic start generated code]*/ 19027db96d56Sopenharmony_ci 19037db96d56Sopenharmony_cistatic PyObject * 19047db96d56Sopenharmony_cigc_freeze_impl(PyObject *module) 19057db96d56Sopenharmony_ci/*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/ 19067db96d56Sopenharmony_ci{ 19077db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 19087db96d56Sopenharmony_ci for (int i = 0; i < NUM_GENERATIONS; ++i) { 19097db96d56Sopenharmony_ci gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head); 19107db96d56Sopenharmony_ci gcstate->generations[i].count = 0; 19117db96d56Sopenharmony_ci } 19127db96d56Sopenharmony_ci Py_RETURN_NONE; 19137db96d56Sopenharmony_ci} 19147db96d56Sopenharmony_ci 19157db96d56Sopenharmony_ci/*[clinic input] 19167db96d56Sopenharmony_cigc.unfreeze 19177db96d56Sopenharmony_ci 19187db96d56Sopenharmony_ciUnfreeze all objects in the permanent generation. 19197db96d56Sopenharmony_ci 19207db96d56Sopenharmony_ciPut all objects in the permanent generation back into oldest generation. 19217db96d56Sopenharmony_ci[clinic start generated code]*/ 19227db96d56Sopenharmony_ci 19237db96d56Sopenharmony_cistatic PyObject * 19247db96d56Sopenharmony_cigc_unfreeze_impl(PyObject *module) 19257db96d56Sopenharmony_ci/*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/ 19267db96d56Sopenharmony_ci{ 19277db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 19287db96d56Sopenharmony_ci gc_list_merge(&gcstate->permanent_generation.head, 19297db96d56Sopenharmony_ci GEN_HEAD(gcstate, NUM_GENERATIONS-1)); 19307db96d56Sopenharmony_ci Py_RETURN_NONE; 19317db96d56Sopenharmony_ci} 19327db96d56Sopenharmony_ci 19337db96d56Sopenharmony_ci/*[clinic input] 19347db96d56Sopenharmony_cigc.get_freeze_count -> Py_ssize_t 19357db96d56Sopenharmony_ci 19367db96d56Sopenharmony_ciReturn the number of objects in the permanent generation. 19377db96d56Sopenharmony_ci[clinic start generated code]*/ 19387db96d56Sopenharmony_ci 19397db96d56Sopenharmony_cistatic Py_ssize_t 19407db96d56Sopenharmony_cigc_get_freeze_count_impl(PyObject *module) 19417db96d56Sopenharmony_ci/*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/ 19427db96d56Sopenharmony_ci{ 19437db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 19447db96d56Sopenharmony_ci return gc_list_size(&gcstate->permanent_generation.head); 19457db96d56Sopenharmony_ci} 19467db96d56Sopenharmony_ci 19477db96d56Sopenharmony_ci 19487db96d56Sopenharmony_ciPyDoc_STRVAR(gc__doc__, 19497db96d56Sopenharmony_ci"This module provides access to the garbage collector for reference cycles.\n" 19507db96d56Sopenharmony_ci"\n" 19517db96d56Sopenharmony_ci"enable() -- Enable automatic garbage collection.\n" 19527db96d56Sopenharmony_ci"disable() -- Disable automatic garbage collection.\n" 19537db96d56Sopenharmony_ci"isenabled() -- Returns true if automatic collection is enabled.\n" 19547db96d56Sopenharmony_ci"collect() -- Do a full collection right now.\n" 19557db96d56Sopenharmony_ci"get_count() -- Return the current collection counts.\n" 19567db96d56Sopenharmony_ci"get_stats() -- Return list of dictionaries containing per-generation stats.\n" 19577db96d56Sopenharmony_ci"set_debug() -- Set debugging flags.\n" 19587db96d56Sopenharmony_ci"get_debug() -- Get debugging flags.\n" 19597db96d56Sopenharmony_ci"set_threshold() -- Set the collection thresholds.\n" 19607db96d56Sopenharmony_ci"get_threshold() -- Return the current the collection thresholds.\n" 19617db96d56Sopenharmony_ci"get_objects() -- Return a list of all objects tracked by the collector.\n" 19627db96d56Sopenharmony_ci"is_tracked() -- Returns true if a given object is tracked.\n" 19637db96d56Sopenharmony_ci"is_finalized() -- Returns true if a given object has been already finalized.\n" 19647db96d56Sopenharmony_ci"get_referrers() -- Return the list of objects that refer to an object.\n" 19657db96d56Sopenharmony_ci"get_referents() -- Return the list of objects that an object refers to.\n" 19667db96d56Sopenharmony_ci"freeze() -- Freeze all tracked objects and ignore them for future collections.\n" 19677db96d56Sopenharmony_ci"unfreeze() -- Unfreeze all objects in the permanent generation.\n" 19687db96d56Sopenharmony_ci"get_freeze_count() -- Return the number of objects in the permanent generation.\n"); 19697db96d56Sopenharmony_ci 19707db96d56Sopenharmony_cistatic PyMethodDef GcMethods[] = { 19717db96d56Sopenharmony_ci GC_ENABLE_METHODDEF 19727db96d56Sopenharmony_ci GC_DISABLE_METHODDEF 19737db96d56Sopenharmony_ci GC_ISENABLED_METHODDEF 19747db96d56Sopenharmony_ci GC_SET_DEBUG_METHODDEF 19757db96d56Sopenharmony_ci GC_GET_DEBUG_METHODDEF 19767db96d56Sopenharmony_ci GC_GET_COUNT_METHODDEF 19777db96d56Sopenharmony_ci {"set_threshold", gc_set_threshold, METH_VARARGS, gc_set_thresh__doc__}, 19787db96d56Sopenharmony_ci GC_GET_THRESHOLD_METHODDEF 19797db96d56Sopenharmony_ci GC_COLLECT_METHODDEF 19807db96d56Sopenharmony_ci GC_GET_OBJECTS_METHODDEF 19817db96d56Sopenharmony_ci GC_GET_STATS_METHODDEF 19827db96d56Sopenharmony_ci GC_IS_TRACKED_METHODDEF 19837db96d56Sopenharmony_ci GC_IS_FINALIZED_METHODDEF 19847db96d56Sopenharmony_ci {"get_referrers", gc_get_referrers, METH_VARARGS, 19857db96d56Sopenharmony_ci gc_get_referrers__doc__}, 19867db96d56Sopenharmony_ci {"get_referents", gc_get_referents, METH_VARARGS, 19877db96d56Sopenharmony_ci gc_get_referents__doc__}, 19887db96d56Sopenharmony_ci GC_FREEZE_METHODDEF 19897db96d56Sopenharmony_ci GC_UNFREEZE_METHODDEF 19907db96d56Sopenharmony_ci GC_GET_FREEZE_COUNT_METHODDEF 19917db96d56Sopenharmony_ci {NULL, NULL} /* Sentinel */ 19927db96d56Sopenharmony_ci}; 19937db96d56Sopenharmony_ci 19947db96d56Sopenharmony_cistatic int 19957db96d56Sopenharmony_cigcmodule_exec(PyObject *module) 19967db96d56Sopenharmony_ci{ 19977db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 19987db96d56Sopenharmony_ci 19997db96d56Sopenharmony_ci /* garbage and callbacks are initialized by _PyGC_Init() early in 20007db96d56Sopenharmony_ci * interpreter lifecycle. */ 20017db96d56Sopenharmony_ci assert(gcstate->garbage != NULL); 20027db96d56Sopenharmony_ci if (PyModule_AddObjectRef(module, "garbage", gcstate->garbage) < 0) { 20037db96d56Sopenharmony_ci return -1; 20047db96d56Sopenharmony_ci } 20057db96d56Sopenharmony_ci assert(gcstate->callbacks != NULL); 20067db96d56Sopenharmony_ci if (PyModule_AddObjectRef(module, "callbacks", gcstate->callbacks) < 0) { 20077db96d56Sopenharmony_ci return -1; 20087db96d56Sopenharmony_ci } 20097db96d56Sopenharmony_ci 20107db96d56Sopenharmony_ci#define ADD_INT(NAME) if (PyModule_AddIntConstant(module, #NAME, NAME) < 0) { return -1; } 20117db96d56Sopenharmony_ci ADD_INT(DEBUG_STATS); 20127db96d56Sopenharmony_ci ADD_INT(DEBUG_COLLECTABLE); 20137db96d56Sopenharmony_ci ADD_INT(DEBUG_UNCOLLECTABLE); 20147db96d56Sopenharmony_ci ADD_INT(DEBUG_SAVEALL); 20157db96d56Sopenharmony_ci ADD_INT(DEBUG_LEAK); 20167db96d56Sopenharmony_ci#undef ADD_INT 20177db96d56Sopenharmony_ci return 0; 20187db96d56Sopenharmony_ci} 20197db96d56Sopenharmony_ci 20207db96d56Sopenharmony_cistatic PyModuleDef_Slot gcmodule_slots[] = { 20217db96d56Sopenharmony_ci {Py_mod_exec, gcmodule_exec}, 20227db96d56Sopenharmony_ci {0, NULL} 20237db96d56Sopenharmony_ci}; 20247db96d56Sopenharmony_ci 20257db96d56Sopenharmony_cistatic struct PyModuleDef gcmodule = { 20267db96d56Sopenharmony_ci PyModuleDef_HEAD_INIT, 20277db96d56Sopenharmony_ci .m_name = "gc", 20287db96d56Sopenharmony_ci .m_doc = gc__doc__, 20297db96d56Sopenharmony_ci .m_size = 0, // per interpreter state, see: get_gc_state() 20307db96d56Sopenharmony_ci .m_methods = GcMethods, 20317db96d56Sopenharmony_ci .m_slots = gcmodule_slots 20327db96d56Sopenharmony_ci}; 20337db96d56Sopenharmony_ci 20347db96d56Sopenharmony_ciPyMODINIT_FUNC 20357db96d56Sopenharmony_ciPyInit_gc(void) 20367db96d56Sopenharmony_ci{ 20377db96d56Sopenharmony_ci return PyModuleDef_Init(&gcmodule); 20387db96d56Sopenharmony_ci} 20397db96d56Sopenharmony_ci 20407db96d56Sopenharmony_ci/* C API for controlling the state of the garbage collector */ 20417db96d56Sopenharmony_ciint 20427db96d56Sopenharmony_ciPyGC_Enable(void) 20437db96d56Sopenharmony_ci{ 20447db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 20457db96d56Sopenharmony_ci int old_state = gcstate->enabled; 20467db96d56Sopenharmony_ci gcstate->enabled = 1; 20477db96d56Sopenharmony_ci return old_state; 20487db96d56Sopenharmony_ci} 20497db96d56Sopenharmony_ci 20507db96d56Sopenharmony_ciint 20517db96d56Sopenharmony_ciPyGC_Disable(void) 20527db96d56Sopenharmony_ci{ 20537db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 20547db96d56Sopenharmony_ci int old_state = gcstate->enabled; 20557db96d56Sopenharmony_ci gcstate->enabled = 0; 20567db96d56Sopenharmony_ci return old_state; 20577db96d56Sopenharmony_ci} 20587db96d56Sopenharmony_ci 20597db96d56Sopenharmony_ciint 20607db96d56Sopenharmony_ciPyGC_IsEnabled(void) 20617db96d56Sopenharmony_ci{ 20627db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 20637db96d56Sopenharmony_ci return gcstate->enabled; 20647db96d56Sopenharmony_ci} 20657db96d56Sopenharmony_ci 20667db96d56Sopenharmony_ci/* Public API to invoke gc.collect() from C */ 20677db96d56Sopenharmony_ciPy_ssize_t 20687db96d56Sopenharmony_ciPyGC_Collect(void) 20697db96d56Sopenharmony_ci{ 20707db96d56Sopenharmony_ci PyThreadState *tstate = _PyThreadState_GET(); 20717db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 20727db96d56Sopenharmony_ci 20737db96d56Sopenharmony_ci if (!gcstate->enabled) { 20747db96d56Sopenharmony_ci return 0; 20757db96d56Sopenharmony_ci } 20767db96d56Sopenharmony_ci 20777db96d56Sopenharmony_ci Py_ssize_t n; 20787db96d56Sopenharmony_ci if (gcstate->collecting) { 20797db96d56Sopenharmony_ci /* already collecting, don't do anything */ 20807db96d56Sopenharmony_ci n = 0; 20817db96d56Sopenharmony_ci } 20827db96d56Sopenharmony_ci else { 20837db96d56Sopenharmony_ci PyObject *exc, *value, *tb; 20847db96d56Sopenharmony_ci gcstate->collecting = 1; 20857db96d56Sopenharmony_ci _PyErr_Fetch(tstate, &exc, &value, &tb); 20867db96d56Sopenharmony_ci n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1); 20877db96d56Sopenharmony_ci _PyErr_Restore(tstate, exc, value, tb); 20887db96d56Sopenharmony_ci gcstate->collecting = 0; 20897db96d56Sopenharmony_ci } 20907db96d56Sopenharmony_ci 20917db96d56Sopenharmony_ci return n; 20927db96d56Sopenharmony_ci} 20937db96d56Sopenharmony_ci 20947db96d56Sopenharmony_ciPy_ssize_t 20957db96d56Sopenharmony_ci_PyGC_CollectNoFail(PyThreadState *tstate) 20967db96d56Sopenharmony_ci{ 20977db96d56Sopenharmony_ci /* Ideally, this function is only called on interpreter shutdown, 20987db96d56Sopenharmony_ci and therefore not recursively. Unfortunately, when there are daemon 20997db96d56Sopenharmony_ci threads, a daemon thread can start a cyclic garbage collection 21007db96d56Sopenharmony_ci during interpreter shutdown (and then never finish it). 21017db96d56Sopenharmony_ci See http://bugs.python.org/issue8713#msg195178 for an example. 21027db96d56Sopenharmony_ci */ 21037db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 21047db96d56Sopenharmony_ci if (gcstate->collecting) { 21057db96d56Sopenharmony_ci return 0; 21067db96d56Sopenharmony_ci } 21077db96d56Sopenharmony_ci 21087db96d56Sopenharmony_ci Py_ssize_t n; 21097db96d56Sopenharmony_ci gcstate->collecting = 1; 21107db96d56Sopenharmony_ci n = gc_collect_main(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1); 21117db96d56Sopenharmony_ci gcstate->collecting = 0; 21127db96d56Sopenharmony_ci return n; 21137db96d56Sopenharmony_ci} 21147db96d56Sopenharmony_ci 21157db96d56Sopenharmony_civoid 21167db96d56Sopenharmony_ci_PyGC_DumpShutdownStats(PyInterpreterState *interp) 21177db96d56Sopenharmony_ci{ 21187db96d56Sopenharmony_ci GCState *gcstate = &interp->gc; 21197db96d56Sopenharmony_ci if (!(gcstate->debug & DEBUG_SAVEALL) 21207db96d56Sopenharmony_ci && gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) { 21217db96d56Sopenharmony_ci const char *message; 21227db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_UNCOLLECTABLE) 21237db96d56Sopenharmony_ci message = "gc: %zd uncollectable objects at " \ 21247db96d56Sopenharmony_ci "shutdown"; 21257db96d56Sopenharmony_ci else 21267db96d56Sopenharmony_ci message = "gc: %zd uncollectable objects at " \ 21277db96d56Sopenharmony_ci "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them"; 21287db96d56Sopenharmony_ci /* PyErr_WarnFormat does too many things and we are at shutdown, 21297db96d56Sopenharmony_ci the warnings module's dependencies (e.g. linecache) may be gone 21307db96d56Sopenharmony_ci already. */ 21317db96d56Sopenharmony_ci if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, 21327db96d56Sopenharmony_ci "gc", NULL, message, 21337db96d56Sopenharmony_ci PyList_GET_SIZE(gcstate->garbage))) 21347db96d56Sopenharmony_ci PyErr_WriteUnraisable(NULL); 21357db96d56Sopenharmony_ci if (gcstate->debug & DEBUG_UNCOLLECTABLE) { 21367db96d56Sopenharmony_ci PyObject *repr = NULL, *bytes = NULL; 21377db96d56Sopenharmony_ci repr = PyObject_Repr(gcstate->garbage); 21387db96d56Sopenharmony_ci if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) 21397db96d56Sopenharmony_ci PyErr_WriteUnraisable(gcstate->garbage); 21407db96d56Sopenharmony_ci else { 21417db96d56Sopenharmony_ci PySys_WriteStderr( 21427db96d56Sopenharmony_ci " %s\n", 21437db96d56Sopenharmony_ci PyBytes_AS_STRING(bytes) 21447db96d56Sopenharmony_ci ); 21457db96d56Sopenharmony_ci } 21467db96d56Sopenharmony_ci Py_XDECREF(repr); 21477db96d56Sopenharmony_ci Py_XDECREF(bytes); 21487db96d56Sopenharmony_ci } 21497db96d56Sopenharmony_ci } 21507db96d56Sopenharmony_ci} 21517db96d56Sopenharmony_ci 21527db96d56Sopenharmony_ci 21537db96d56Sopenharmony_cistatic void 21547db96d56Sopenharmony_cigc_fini_untrack(PyGC_Head *list) 21557db96d56Sopenharmony_ci{ 21567db96d56Sopenharmony_ci PyGC_Head *gc; 21577db96d56Sopenharmony_ci for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) { 21587db96d56Sopenharmony_ci PyObject *op = FROM_GC(gc); 21597db96d56Sopenharmony_ci _PyObject_GC_UNTRACK(op); 21607db96d56Sopenharmony_ci // gh-92036: If a deallocator function expect the object to be tracked 21617db96d56Sopenharmony_ci // by the GC (ex: func_dealloc()), it can crash if called on an object 21627db96d56Sopenharmony_ci // which is no longer tracked by the GC. Leak one strong reference on 21637db96d56Sopenharmony_ci // purpose so the object is never deleted and its deallocator is not 21647db96d56Sopenharmony_ci // called. 21657db96d56Sopenharmony_ci Py_INCREF(op); 21667db96d56Sopenharmony_ci } 21677db96d56Sopenharmony_ci} 21687db96d56Sopenharmony_ci 21697db96d56Sopenharmony_ci 21707db96d56Sopenharmony_civoid 21717db96d56Sopenharmony_ci_PyGC_Fini(PyInterpreterState *interp) 21727db96d56Sopenharmony_ci{ 21737db96d56Sopenharmony_ci GCState *gcstate = &interp->gc; 21747db96d56Sopenharmony_ci Py_CLEAR(gcstate->garbage); 21757db96d56Sopenharmony_ci Py_CLEAR(gcstate->callbacks); 21767db96d56Sopenharmony_ci 21777db96d56Sopenharmony_ci if (!_Py_IsMainInterpreter(interp)) { 21787db96d56Sopenharmony_ci // bpo-46070: Explicitly untrack all objects currently tracked by the 21797db96d56Sopenharmony_ci // GC. Otherwise, if an object is used later by another interpreter, 21807db96d56Sopenharmony_ci // calling PyObject_GC_UnTrack() on the object crashs if the previous 21817db96d56Sopenharmony_ci // or the next object of the PyGC_Head structure became a dangling 21827db96d56Sopenharmony_ci // pointer. 21837db96d56Sopenharmony_ci for (int i = 0; i < NUM_GENERATIONS; i++) { 21847db96d56Sopenharmony_ci PyGC_Head *gen = GEN_HEAD(gcstate, i); 21857db96d56Sopenharmony_ci gc_fini_untrack(gen); 21867db96d56Sopenharmony_ci } 21877db96d56Sopenharmony_ci } 21887db96d56Sopenharmony_ci} 21897db96d56Sopenharmony_ci 21907db96d56Sopenharmony_ci/* for debugging */ 21917db96d56Sopenharmony_civoid 21927db96d56Sopenharmony_ci_PyGC_Dump(PyGC_Head *g) 21937db96d56Sopenharmony_ci{ 21947db96d56Sopenharmony_ci _PyObject_Dump(FROM_GC(g)); 21957db96d56Sopenharmony_ci} 21967db96d56Sopenharmony_ci 21977db96d56Sopenharmony_ci 21987db96d56Sopenharmony_ci#ifdef Py_DEBUG 21997db96d56Sopenharmony_cistatic int 22007db96d56Sopenharmony_civisit_validate(PyObject *op, void *parent_raw) 22017db96d56Sopenharmony_ci{ 22027db96d56Sopenharmony_ci PyObject *parent = _PyObject_CAST(parent_raw); 22037db96d56Sopenharmony_ci if (_PyObject_IsFreed(op)) { 22047db96d56Sopenharmony_ci _PyObject_ASSERT_FAILED_MSG(parent, 22057db96d56Sopenharmony_ci "PyObject_GC_Track() object is not valid"); 22067db96d56Sopenharmony_ci } 22077db96d56Sopenharmony_ci return 0; 22087db96d56Sopenharmony_ci} 22097db96d56Sopenharmony_ci#endif 22107db96d56Sopenharmony_ci 22117db96d56Sopenharmony_ci 22127db96d56Sopenharmony_ci/* extension modules might be compiled with GC support so these 22137db96d56Sopenharmony_ci functions must always be available */ 22147db96d56Sopenharmony_ci 22157db96d56Sopenharmony_civoid 22167db96d56Sopenharmony_ciPyObject_GC_Track(void *op_raw) 22177db96d56Sopenharmony_ci{ 22187db96d56Sopenharmony_ci PyObject *op = _PyObject_CAST(op_raw); 22197db96d56Sopenharmony_ci if (_PyObject_GC_IS_TRACKED(op)) { 22207db96d56Sopenharmony_ci _PyObject_ASSERT_FAILED_MSG(op, 22217db96d56Sopenharmony_ci "object already tracked " 22227db96d56Sopenharmony_ci "by the garbage collector"); 22237db96d56Sopenharmony_ci } 22247db96d56Sopenharmony_ci _PyObject_GC_TRACK(op); 22257db96d56Sopenharmony_ci 22267db96d56Sopenharmony_ci#ifdef Py_DEBUG 22277db96d56Sopenharmony_ci /* Check that the object is valid: validate objects traversed 22287db96d56Sopenharmony_ci by tp_traverse() */ 22297db96d56Sopenharmony_ci traverseproc traverse = Py_TYPE(op)->tp_traverse; 22307db96d56Sopenharmony_ci (void)traverse(op, visit_validate, op); 22317db96d56Sopenharmony_ci#endif 22327db96d56Sopenharmony_ci} 22337db96d56Sopenharmony_ci 22347db96d56Sopenharmony_civoid 22357db96d56Sopenharmony_ciPyObject_GC_UnTrack(void *op_raw) 22367db96d56Sopenharmony_ci{ 22377db96d56Sopenharmony_ci PyObject *op = _PyObject_CAST(op_raw); 22387db96d56Sopenharmony_ci /* Obscure: the Py_TRASHCAN mechanism requires that we be able to 22397db96d56Sopenharmony_ci * call PyObject_GC_UnTrack twice on an object. 22407db96d56Sopenharmony_ci */ 22417db96d56Sopenharmony_ci if (_PyObject_GC_IS_TRACKED(op)) { 22427db96d56Sopenharmony_ci _PyObject_GC_UNTRACK(op); 22437db96d56Sopenharmony_ci } 22447db96d56Sopenharmony_ci} 22457db96d56Sopenharmony_ci 22467db96d56Sopenharmony_ciint 22477db96d56Sopenharmony_ciPyObject_IS_GC(PyObject *obj) 22487db96d56Sopenharmony_ci{ 22497db96d56Sopenharmony_ci return _PyObject_IS_GC(obj); 22507db96d56Sopenharmony_ci} 22517db96d56Sopenharmony_ci 22527db96d56Sopenharmony_civoid 22537db96d56Sopenharmony_ci_PyObject_GC_Link(PyObject *op) 22547db96d56Sopenharmony_ci{ 22557db96d56Sopenharmony_ci PyGC_Head *g = AS_GC(op); 22567db96d56Sopenharmony_ci assert(((uintptr_t)g & (sizeof(uintptr_t)-1)) == 0); // g must be correctly aligned 22577db96d56Sopenharmony_ci 22587db96d56Sopenharmony_ci PyThreadState *tstate = _PyThreadState_GET(); 22597db96d56Sopenharmony_ci GCState *gcstate = &tstate->interp->gc; 22607db96d56Sopenharmony_ci g->_gc_next = 0; 22617db96d56Sopenharmony_ci g->_gc_prev = 0; 22627db96d56Sopenharmony_ci gcstate->generations[0].count++; /* number of allocated GC objects */ 22637db96d56Sopenharmony_ci if (gcstate->generations[0].count > gcstate->generations[0].threshold && 22647db96d56Sopenharmony_ci gcstate->enabled && 22657db96d56Sopenharmony_ci gcstate->generations[0].threshold && 22667db96d56Sopenharmony_ci !gcstate->collecting && 22677db96d56Sopenharmony_ci !_PyErr_Occurred(tstate)) 22687db96d56Sopenharmony_ci { 22697db96d56Sopenharmony_ci gcstate->collecting = 1; 22707db96d56Sopenharmony_ci gc_collect_generations(tstate); 22717db96d56Sopenharmony_ci gcstate->collecting = 0; 22727db96d56Sopenharmony_ci } 22737db96d56Sopenharmony_ci} 22747db96d56Sopenharmony_ci 22757db96d56Sopenharmony_cistatic PyObject * 22767db96d56Sopenharmony_cigc_alloc(size_t basicsize, size_t presize) 22777db96d56Sopenharmony_ci{ 22787db96d56Sopenharmony_ci PyThreadState *tstate = _PyThreadState_GET(); 22797db96d56Sopenharmony_ci if (basicsize > PY_SSIZE_T_MAX - presize) { 22807db96d56Sopenharmony_ci return _PyErr_NoMemory(tstate); 22817db96d56Sopenharmony_ci } 22827db96d56Sopenharmony_ci size_t size = presize + basicsize; 22837db96d56Sopenharmony_ci char *mem = PyObject_Malloc(size); 22847db96d56Sopenharmony_ci if (mem == NULL) { 22857db96d56Sopenharmony_ci return _PyErr_NoMemory(tstate); 22867db96d56Sopenharmony_ci } 22877db96d56Sopenharmony_ci ((PyObject **)mem)[0] = NULL; 22887db96d56Sopenharmony_ci ((PyObject **)mem)[1] = NULL; 22897db96d56Sopenharmony_ci PyObject *op = (PyObject *)(mem + presize); 22907db96d56Sopenharmony_ci _PyObject_GC_Link(op); 22917db96d56Sopenharmony_ci return op; 22927db96d56Sopenharmony_ci} 22937db96d56Sopenharmony_ci 22947db96d56Sopenharmony_ciPyObject * 22957db96d56Sopenharmony_ci_PyObject_GC_New(PyTypeObject *tp) 22967db96d56Sopenharmony_ci{ 22977db96d56Sopenharmony_ci size_t presize = _PyType_PreHeaderSize(tp); 22987db96d56Sopenharmony_ci PyObject *op = gc_alloc(_PyObject_SIZE(tp), presize); 22997db96d56Sopenharmony_ci if (op == NULL) { 23007db96d56Sopenharmony_ci return NULL; 23017db96d56Sopenharmony_ci } 23027db96d56Sopenharmony_ci _PyObject_Init(op, tp); 23037db96d56Sopenharmony_ci return op; 23047db96d56Sopenharmony_ci} 23057db96d56Sopenharmony_ci 23067db96d56Sopenharmony_ciPyVarObject * 23077db96d56Sopenharmony_ci_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) 23087db96d56Sopenharmony_ci{ 23097db96d56Sopenharmony_ci size_t size; 23107db96d56Sopenharmony_ci PyVarObject *op; 23117db96d56Sopenharmony_ci 23127db96d56Sopenharmony_ci if (nitems < 0) { 23137db96d56Sopenharmony_ci PyErr_BadInternalCall(); 23147db96d56Sopenharmony_ci return NULL; 23157db96d56Sopenharmony_ci } 23167db96d56Sopenharmony_ci size_t presize = _PyType_PreHeaderSize(tp); 23177db96d56Sopenharmony_ci size = _PyObject_VAR_SIZE(tp, nitems); 23187db96d56Sopenharmony_ci op = (PyVarObject *)gc_alloc(size, presize); 23197db96d56Sopenharmony_ci if (op == NULL) { 23207db96d56Sopenharmony_ci return NULL; 23217db96d56Sopenharmony_ci } 23227db96d56Sopenharmony_ci _PyObject_InitVar(op, tp, nitems); 23237db96d56Sopenharmony_ci return op; 23247db96d56Sopenharmony_ci} 23257db96d56Sopenharmony_ci 23267db96d56Sopenharmony_ciPyVarObject * 23277db96d56Sopenharmony_ci_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) 23287db96d56Sopenharmony_ci{ 23297db96d56Sopenharmony_ci const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems); 23307db96d56Sopenharmony_ci _PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op)); 23317db96d56Sopenharmony_ci if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { 23327db96d56Sopenharmony_ci return (PyVarObject *)PyErr_NoMemory(); 23337db96d56Sopenharmony_ci } 23347db96d56Sopenharmony_ci 23357db96d56Sopenharmony_ci PyGC_Head *g = AS_GC(op); 23367db96d56Sopenharmony_ci g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize); 23377db96d56Sopenharmony_ci if (g == NULL) 23387db96d56Sopenharmony_ci return (PyVarObject *)PyErr_NoMemory(); 23397db96d56Sopenharmony_ci op = (PyVarObject *) FROM_GC(g); 23407db96d56Sopenharmony_ci Py_SET_SIZE(op, nitems); 23417db96d56Sopenharmony_ci return op; 23427db96d56Sopenharmony_ci} 23437db96d56Sopenharmony_ci 23447db96d56Sopenharmony_civoid 23457db96d56Sopenharmony_ciPyObject_GC_Del(void *op) 23467db96d56Sopenharmony_ci{ 23477db96d56Sopenharmony_ci size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); 23487db96d56Sopenharmony_ci PyGC_Head *g = AS_GC(op); 23497db96d56Sopenharmony_ci if (_PyObject_GC_IS_TRACKED(op)) { 23507db96d56Sopenharmony_ci#ifdef Py_DEBUG 23517db96d56Sopenharmony_ci if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, 23527db96d56Sopenharmony_ci "gc", NULL, "Object of type %s is not untracked before destruction", 23537db96d56Sopenharmony_ci ((PyObject*)op)->ob_type->tp_name)) { 23547db96d56Sopenharmony_ci PyErr_WriteUnraisable(NULL); 23557db96d56Sopenharmony_ci } 23567db96d56Sopenharmony_ci#endif 23577db96d56Sopenharmony_ci gc_list_remove(g); 23587db96d56Sopenharmony_ci } 23597db96d56Sopenharmony_ci GCState *gcstate = get_gc_state(); 23607db96d56Sopenharmony_ci if (gcstate->generations[0].count > 0) { 23617db96d56Sopenharmony_ci gcstate->generations[0].count--; 23627db96d56Sopenharmony_ci } 23637db96d56Sopenharmony_ci PyObject_Free(((char *)op)-presize); 23647db96d56Sopenharmony_ci} 23657db96d56Sopenharmony_ci 23667db96d56Sopenharmony_ciint 23677db96d56Sopenharmony_ciPyObject_GC_IsTracked(PyObject* obj) 23687db96d56Sopenharmony_ci{ 23697db96d56Sopenharmony_ci if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) { 23707db96d56Sopenharmony_ci return 1; 23717db96d56Sopenharmony_ci } 23727db96d56Sopenharmony_ci return 0; 23737db96d56Sopenharmony_ci} 23747db96d56Sopenharmony_ci 23757db96d56Sopenharmony_ciint 23767db96d56Sopenharmony_ciPyObject_GC_IsFinalized(PyObject *obj) 23777db96d56Sopenharmony_ci{ 23787db96d56Sopenharmony_ci if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { 23797db96d56Sopenharmony_ci return 1; 23807db96d56Sopenharmony_ci } 23817db96d56Sopenharmony_ci return 0; 23827db96d56Sopenharmony_ci} 2383