@@ -71,6 +71,10 @@ _PyGC_Initialize(struct _gc_runtime_state *state)
7171 state -> generations [i ] = generations [i ];
7272 };
7373 state -> generation0 = GEN_HEAD (0 );
74+ struct gc_generation permanent_generation = {
75+ {{& state -> permanent_generation .head , & state -> permanent_generation .head , 0 }}, 0 , 0
76+ };
77+ state -> permanent_generation = permanent_generation ;
7478}
7579
7680/*--------------------------------------------------------------------------
@@ -813,6 +817,8 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
813817 for (i = 0 ; i < NUM_GENERATIONS ; i ++ )
814818 PySys_FormatStderr (" %zd" ,
815819 gc_list_size (GEN_HEAD (i )));
820+ PySys_WriteStderr ("\ngc: objects in permanent generation: %zd" ,
821+ gc_list_size (& _PyRuntime .gc .permanent_generation .head ));
816822 t1 = _PyTime_GetMonotonicClock ();
817823
818824 PySys_WriteStderr ("\n" );
@@ -1405,6 +1411,56 @@ gc_is_tracked(PyObject *module, PyObject *obj)
14051411 return result ;
14061412}
14071413
1414+ /*[clinic input]
1415+ gc.freeze
1416+
1417+ Freeze all current tracked objects and ignore them for future collections.
1418+
1419+ This can be used before a POSIX fork() call to make the gc copy-on-write friendly.
1420+ Note: collection before a POSIX fork() call may free pages for future allocation
1421+ which can cause copy-on-write.
1422+ [clinic start generated code]*/
1423+
1424+ static PyObject *
1425+ gc_freeze_impl (PyObject * module )
1426+ /*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/
1427+ {
1428+ for (int i = 0 ; i < NUM_GENERATIONS ; ++ i ) {
1429+ gc_list_merge (GEN_HEAD (i ), & _PyRuntime .gc .permanent_generation .head );
1430+ _PyRuntime .gc .generations [i ].count = 0 ;
1431+ }
1432+ Py_RETURN_NONE ;
1433+ }
1434+
1435+ /*[clinic input]
1436+ gc.unfreeze
1437+
1438+ Unfreeze all objects in the permanent generation.
1439+
1440+ Put all objects in the permanent generation back into oldest generation.
1441+ [clinic start generated code]*/
1442+
1443+ static PyObject *
1444+ gc_unfreeze_impl (PyObject * module )
1445+ /*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/
1446+ {
1447+ gc_list_merge (& _PyRuntime .gc .permanent_generation .head , GEN_HEAD (NUM_GENERATIONS - 1 ));
1448+ Py_RETURN_NONE ;
1449+ }
1450+
1451+ /*[clinic input]
1452+ gc.get_freeze_count -> int
1453+
1454+ Return the number of objects in the permanent generation.
1455+ [clinic start generated code]*/
1456+
1457+ static int
1458+ gc_get_freeze_count_impl (PyObject * module )
1459+ /*[clinic end generated code: output=e4e2ebcc77e5cbf3 input=4b759db880a3c6e4]*/
1460+ {
1461+ return gc_list_size (& _PyRuntime .gc .permanent_generation .head );
1462+ }
1463+
14081464
14091465PyDoc_STRVAR (gc__doc__ ,
14101466"This module provides access to the garbage collector for reference cycles.\n"
@@ -1422,7 +1478,10 @@ PyDoc_STRVAR(gc__doc__,
14221478"get_objects() -- Return a list of all objects tracked by the collector.\n"
14231479"is_tracked() -- Returns true if a given object is tracked.\n"
14241480"get_referrers() -- Return the list of objects that refer to an object.\n"
1425- "get_referents() -- Return the list of objects that an object refers to.\n" );
1481+ "get_referents() -- Return the list of objects that an object refers to.\n"
1482+ "freeze() -- Freeze all tracked objects and ignore them for future collections.\n"
1483+ "unfreeze() -- Unfreeze all objects in the permanent generation.\n"
1484+ "get_freeze_count() -- Return the number of objects in the permanent generation.\n" );
14261485
14271486static PyMethodDef GcMethods [] = {
14281487 GC_ENABLE_METHODDEF
@@ -1441,6 +1500,9 @@ static PyMethodDef GcMethods[] = {
14411500 gc_get_referrers__doc__ },
14421501 {"get_referents" , gc_get_referents , METH_VARARGS ,
14431502 gc_get_referents__doc__ },
1503+ GC_FREEZE_METHODDEF
1504+ GC_UNFREEZE_METHODDEF
1505+ GC_GET_FREEZE_COUNT_METHODDEF
14441506 {NULL , NULL } /* Sentinel */
14451507};
14461508
0 commit comments