| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | #ifndef Py_INTERNAL_GC_H
 | 
					
						
							|  |  |  | #define Py_INTERNAL_GC_H
 | 
					
						
							|  |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef Py_BUILD_CORE
 | 
					
						
							|  |  |  | #  error "this header requires Py_BUILD_CORE define"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* GC information is stored BEFORE the object structure. */ | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     // Pointer to next object in the list.
 | 
					
						
							|  |  |  |     // 0 means the object is not tracked
 | 
					
						
							|  |  |  |     uintptr_t _gc_next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Pointer to previous object in the list.
 | 
					
						
							|  |  |  |     // Lowest two bits are used for flags documented later.
 | 
					
						
							|  |  |  |     uintptr_t _gc_prev; | 
					
						
							|  |  |  | } PyGC_Head; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-11 13:37:18 +02:00
										 |  |  | static inline PyGC_Head* _Py_AS_GC(PyObject *op) { | 
					
						
							|  |  |  |     return (_Py_CAST(PyGC_Head*, op) - 1); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-02-28 15:15:48 -07:00
										 |  |  | #define _PyGC_Head_UNUSED PyGC_Head
 | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* True if the object is currently tracked by the GC. */ | 
					
						
							| 
									
										
										
										
											2022-05-11 13:37:18 +02:00
										 |  |  | static inline int _PyObject_GC_IS_TRACKED(PyObject *op) { | 
					
						
							|  |  |  |     PyGC_Head *gc = _Py_AS_GC(op); | 
					
						
							|  |  |  |     return (gc->_gc_next != 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #define _PyObject_GC_IS_TRACKED(op) _PyObject_GC_IS_TRACKED(_Py_CAST(PyObject*, op))
 | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* True if the object may be tracked by the GC in the future, or already is.
 | 
					
						
							|  |  |  |    This can be useful to implement some optimizations. */ | 
					
						
							| 
									
										
										
										
											2022-05-11 13:37:18 +02:00
										 |  |  | static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) { | 
					
						
							|  |  |  |     if (!PyObject_IS_GC(obj)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyTuple_CheckExact(obj)) { | 
					
						
							|  |  |  |         return _PyObject_GC_IS_TRACKED(obj); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Bit flags for _gc_prev */ | 
					
						
							|  |  |  | /* Bit 0 is set when tp_finalize is called */ | 
					
						
							|  |  |  | #define _PyGC_PREV_MASK_FINALIZED  (1)
 | 
					
						
							|  |  |  | /* Bit 1 is set when the object is in generation which is GCed currently. */ | 
					
						
							|  |  |  | #define _PyGC_PREV_MASK_COLLECTING (2)
 | 
					
						
							|  |  |  | /* The (N-2) most significant bits contain the real address. */ | 
					
						
							|  |  |  | #define _PyGC_PREV_SHIFT           (2)
 | 
					
						
							|  |  |  | #define _PyGC_PREV_MASK            (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Lowest bit of _gc_next is used for flags only in GC.
 | 
					
						
							|  |  |  | // But it is always 0 for normal code.
 | 
					
						
							| 
									
										
										
										
											2022-05-11 13:37:18 +02:00
										 |  |  | static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) { | 
					
						
							|  |  |  |     uintptr_t next = gc->_gc_next; | 
					
						
							|  |  |  |     return _Py_CAST(PyGC_Head*, next); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) { | 
					
						
							|  |  |  |     gc->_gc_next = _Py_CAST(uintptr_t, next); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
 | 
					
						
							| 
									
										
										
										
											2022-05-11 13:37:18 +02:00
										 |  |  | static inline PyGC_Head* _PyGCHead_PREV(PyGC_Head *gc) { | 
					
						
							|  |  |  |     uintptr_t prev = (gc->_gc_prev & _PyGC_PREV_MASK); | 
					
						
							|  |  |  |     return _Py_CAST(PyGC_Head*, prev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) { | 
					
						
							|  |  |  |     uintptr_t uprev = _Py_CAST(uintptr_t, prev); | 
					
						
							|  |  |  |     assert((uprev & ~_PyGC_PREV_MASK) == 0); | 
					
						
							|  |  |  |     gc->_gc_prev = ((gc->_gc_prev & ~_PyGC_PREV_MASK) | uprev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int _PyGCHead_FINALIZED(PyGC_Head *gc) { | 
					
						
							|  |  |  |     return ((gc->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void _PyGCHead_SET_FINALIZED(PyGC_Head *gc) { | 
					
						
							|  |  |  |     gc->_gc_prev |= _PyGC_PREV_MASK_FINALIZED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int _PyGC_FINALIZED(PyObject *op) { | 
					
						
							|  |  |  |     PyGC_Head *gc = _Py_AS_GC(op); | 
					
						
							|  |  |  |     return _PyGCHead_FINALIZED(gc); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void _PyGC_SET_FINALIZED(PyObject *op) { | 
					
						
							|  |  |  |     PyGC_Head *gc = _Py_AS_GC(op); | 
					
						
							|  |  |  |     _PyGCHead_SET_FINALIZED(gc); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-14 18:30:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* GC runtime state */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* If we change this, we need to change the default value in the
 | 
					
						
							|  |  |  |    signature of gc.collect. */ | 
					
						
							|  |  |  | #define NUM_GENERATIONS 3
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |    NOTE: about untracking of mutable objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Certain types of container cannot participate in a reference cycle, and | 
					
						
							|  |  |  |    so do not need to be tracked by the garbage collector. Untracking these | 
					
						
							|  |  |  |    objects reduces the cost of garbage collections. However, determining | 
					
						
							|  |  |  |    which objects may be untracked is not free, and the costs must be | 
					
						
							|  |  |  |    weighed against the benefits for garbage collection. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    There are two possible strategies for when to untrack a container: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    i) When the container is created. | 
					
						
							|  |  |  |    ii) When the container is examined by the garbage collector. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Tuples containing only immutable objects (integers, strings etc, and | 
					
						
							|  |  |  |    recursively, tuples of immutable objects) do not need to be tracked. | 
					
						
							|  |  |  |    The interpreter creates a large number of tuples, many of which will | 
					
						
							|  |  |  |    not survive until garbage collection. It is therefore not worthwhile | 
					
						
							|  |  |  |    to untrack eligible tuples at creation time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Instead, all tuples except the empty tuple are tracked when created. | 
					
						
							|  |  |  |    During garbage collection it is determined whether any surviving tuples | 
					
						
							|  |  |  |    can be untracked. A tuple can be untracked if all of its contents are | 
					
						
							|  |  |  |    already not tracked. Tuples are examined for untracking in all garbage | 
					
						
							|  |  |  |    collection cycles. It may take more than one cycle to untrack a tuple. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Dictionaries containing only immutable objects also do not need to be | 
					
						
							|  |  |  |    tracked. Dictionaries are untracked when created. If a tracked item is | 
					
						
							|  |  |  |    inserted into a dictionary (either as a key or value), the dictionary | 
					
						
							|  |  |  |    becomes tracked. During a full garbage collection (all generations), | 
					
						
							|  |  |  |    the collector will untrack any dictionaries whose contents are not | 
					
						
							|  |  |  |    tracked. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    The module provides the python function is_tracked(obj), which returns | 
					
						
							|  |  |  |    the CURRENT tracking status of the object. Subsequent garbage | 
					
						
							|  |  |  |    collections may change the tracking status of the object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Untracking of certain containers was introduced in issue #4688, and | 
					
						
							|  |  |  |    the algorithm was refined in response to issue #14775. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct gc_generation { | 
					
						
							|  |  |  |     PyGC_Head head; | 
					
						
							|  |  |  |     int threshold; /* collection threshold */ | 
					
						
							|  |  |  |     int count; /* count of allocations or collections of younger
 | 
					
						
							|  |  |  |                   generations */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Running stats per generation */ | 
					
						
							|  |  |  | struct gc_generation_stats { | 
					
						
							|  |  |  |     /* total number of collections */ | 
					
						
							|  |  |  |     Py_ssize_t collections; | 
					
						
							|  |  |  |     /* total number of collected objects */ | 
					
						
							|  |  |  |     Py_ssize_t collected; | 
					
						
							|  |  |  |     /* total number of uncollectable objects (put into gc.garbage) */ | 
					
						
							|  |  |  |     Py_ssize_t uncollectable; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _gc_runtime_state { | 
					
						
							|  |  |  |     /* List of objects that still need to be cleaned up, singly linked
 | 
					
						
							|  |  |  |      * via their gc headers' gc_prev pointers.  */ | 
					
						
							|  |  |  |     PyObject *trash_delete_later; | 
					
						
							|  |  |  |     /* Current call-stack depth of tp_dealloc calls. */ | 
					
						
							|  |  |  |     int trash_delete_nesting; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-13 17:17:28 -07:00
										 |  |  |     /* Is automatic collection enabled? */ | 
					
						
							| 
									
										
										
										
											2020-04-14 18:30:41 +02:00
										 |  |  |     int enabled; | 
					
						
							|  |  |  |     int debug; | 
					
						
							|  |  |  |     /* linked lists of container objects */ | 
					
						
							|  |  |  |     struct gc_generation generations[NUM_GENERATIONS]; | 
					
						
							|  |  |  |     PyGC_Head *generation0; | 
					
						
							|  |  |  |     /* a permanent generation which won't be collected */ | 
					
						
							|  |  |  |     struct gc_generation permanent_generation; | 
					
						
							|  |  |  |     struct gc_generation_stats generation_stats[NUM_GENERATIONS]; | 
					
						
							|  |  |  |     /* true if we are currently running the collector */ | 
					
						
							|  |  |  |     int collecting; | 
					
						
							|  |  |  |     /* list of uncollectable objects */ | 
					
						
							|  |  |  |     PyObject *garbage; | 
					
						
							|  |  |  |     /* a list of callbacks to be invoked when collection is performed */ | 
					
						
							|  |  |  |     PyObject *callbacks; | 
					
						
							|  |  |  |     /* This is the number of objects that survived the last full
 | 
					
						
							|  |  |  |        collection. It approximates the number of long lived objects | 
					
						
							|  |  |  |        tracked by the GC. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        (by "full collection", we mean a collection of the oldest | 
					
						
							|  |  |  |        generation). */ | 
					
						
							|  |  |  |     Py_ssize_t long_lived_total; | 
					
						
							|  |  |  |     /* This is the number of objects that survived all "non-full"
 | 
					
						
							|  |  |  |        collections, and are awaiting to undergo a full collection for | 
					
						
							|  |  |  |        the first time. */ | 
					
						
							|  |  |  |     Py_ssize_t long_lived_pending; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-13 17:17:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 17:00:00 +01:00
										 |  |  | extern void _PyGC_InitState(struct _gc_runtime_state *); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); | 
					
						
							| 
									
										
										
										
											2020-04-14 18:30:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 02:29:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Functions to clear types free lists
 | 
					
						
							| 
									
										
										
										
											2021-02-19 15:10:45 +01:00
										 |  |  | extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); | 
					
						
							|  |  |  | extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); | 
					
						
							|  |  |  | extern void _PyList_ClearFreeList(PyInterpreterState *interp); | 
					
						
							|  |  |  | extern void _PyDict_ClearFreeList(PyInterpreterState *interp); | 
					
						
							|  |  |  | extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); | 
					
						
							|  |  |  | extern void _PyContext_ClearFreeList(PyInterpreterState *interp); | 
					
						
							| 
									
										
										
										
											2020-04-29 02:29:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 11:38:42 +02:00
										 |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #endif /* !Py_INTERNAL_GC_H */
 |