From 6229a31f576fd80e23139dd4a3f8211db9c51969 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 15:11:52 +0200 Subject: [PATCH 01/17] bpo-28254: Add a C-API for controlling the state of the garbage collector. --- Include/objimpl.h | 4 +++ .../2021-04-28-12-33-44.bpo-28254.a2561e.rst | 3 ++ Modules/_testcapimodule.c | 35 +++++++++++++++++++ Modules/gcmodule.c | 31 ++++++++++++---- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst diff --git a/Include/objimpl.h b/Include/objimpl.h index 1408d051ba7efe..e5be89ebc008d6 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -152,6 +152,10 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); /* C equivalent of gc.collect() which ignores the state of gc.enabled. */ PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); +/* C API for controlling the state of the garbage collector */ +PyAPI_FUNC(void) PyGC_Enable(void); +PyAPI_FUNC(void) PyGC_Disable(void); +PyAPI_FUNC(int) PyGC_IsEnabled(void); /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst b/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst new file mode 100644 index 00000000000000..5599e6d0a9c415 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst @@ -0,0 +1,3 @@ +Add new C-API functions to control the state of the garbage collector: +PyGC_Enable(), PyGC_Disable(), PyGC_IsEnabled(), corresponding to the +functions in the ``gc`` module. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index db62aea421c806..a856b6739a2317 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -144,6 +144,40 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored)) #endif } +static PyObject* +test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + int orig_enabled = PyGC_IsEnabled(); + const char* msg = "ok"; + + PyGC_Enable(); + msg = "enable(1)"; + if (!PyGC_IsEnabled()) goto failed; + PyGC_Disable(); + msg = "disable(1)"; + if (PyGC_IsEnabled()) goto failed; + PyGC_Enable(); + msg = "enable(2)"; + if (!PyGC_IsEnabled()) goto failed; + + if (!orig_enabled) { + PyGC_Disable(); + msg = "disable(2)"; + if (PyGC_IsEnabled()) goto failed; + } + + Py_RETURN_NONE; + +failed: + /* Try to clean up if we can. */ + if (orig_enabled) { + PyGC_Enable(); + } else { + PyGC_Disable(); + } + PyErr_Format(TestError, "GC control failed in %s", msg); + return NULL; +} static PyObject* test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) @@ -5544,6 +5578,7 @@ static PyMethodDef TestMethods[] = { {"PyDateTime_DATE_GET", test_PyDateTime_DATE_GET, METH_O}, {"PyDateTime_TIME_GET", test_PyDateTime_TIME_GET, METH_O}, {"PyDateTime_DELTA_GET", test_PyDateTime_DELTA_GET, METH_O}, + {"test_gc_control", test_gc_control, METH_NOARGS}, {"test_list_api", test_list_api, METH_NOARGS}, {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, {"dict_getitem_knownhash", dict_getitem_knownhash, METH_VARARGS}, diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index d6b51426c4e2d8..5e2651894a694f 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1484,8 +1484,7 @@ static PyObject * gc_enable_impl(PyObject *module) /*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/ { - GCState *gcstate = get_gc_state(); - gcstate->enabled = 1; + PyGC_Enable(); Py_RETURN_NONE; } @@ -1499,8 +1498,7 @@ static PyObject * gc_disable_impl(PyObject *module) /*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/ { - GCState *gcstate = get_gc_state(); - gcstate->enabled = 0; + PyGC_Disable(); Py_RETURN_NONE; } @@ -1514,8 +1512,7 @@ static int gc_isenabled_impl(PyObject *module) /*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/ { - GCState *gcstate = get_gc_state(); - return gcstate->enabled; + return PyGC_IsEnabled(); } /*[clinic input] @@ -2081,6 +2078,28 @@ PyGC_Collect(void) return n; } +/* C API for controlling the state of the garbage collector */ +void +PyGC_Enable(void) +{ + GCState *gcstate = get_gc_state(); + gcstate->enabled = 1; +} + +void +PyGC_Disable(void) +{ + GCState *gcstate = get_gc_state(); + gcstate->enabled = 0; +} + +int +PyGC_IsEnabled(void) +{ + GCState *gcstate = get_gc_state(); + return gcstate->enabled; +} + Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate) { From bfbadb90eeac3d6ba5c51f6d2bfe41bfa495ec37 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 15:24:48 +0200 Subject: [PATCH 02/17] bpo-28254: Improve markup and add a What's New entry. --- Doc/whatsnew/3.10.rst | 7 +++++++ .../next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index eeb0c291008e50..a9657d96cb8761 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1691,6 +1691,13 @@ New Features singleton or the ``False`` singleton. (Contributed by Victor Stinner in :issue:`43753`.) +* Add new functions to quickly control the garbage collector from C code: + :c:func:`PyGC_Enable()`, + :c:func:`PyGC_Disable()`, + :c:func:`PyGC_IsEnabled()`. + This previously required importing the :mod:`gc` module and calling + Python functions in it, which is cumbersome from C code. + Porting to Python 3.10 ---------------------- diff --git a/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst b/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst index 5599e6d0a9c415..015acc9803d474 100644 --- a/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst +++ b/Misc/NEWS.d/next/C API/2021-04-28-12-33-44.bpo-28254.a2561e.rst @@ -1,3 +1,3 @@ Add new C-API functions to control the state of the garbage collector: -PyGC_Enable(), PyGC_Disable(), PyGC_IsEnabled(), corresponding to the -functions in the ``gc`` module. +:c:func:`PyGC_Enable()`, :c:func:`PyGC_Disable()`, :c:func:`PyGC_IsEnabled()`, +corresponding to the functions in the :mod:`gc` module. From f41d26976f7dff797a8862f17641b2d2684274b3 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 28 Apr 2021 14:44:09 +0100 Subject: [PATCH 03/17] Apply suggestions from code review --- Doc/whatsnew/3.10.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index a9657d96cb8761..241b3bb66ae6e4 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1695,8 +1695,8 @@ New Features :c:func:`PyGC_Enable()`, :c:func:`PyGC_Disable()`, :c:func:`PyGC_IsEnabled()`. - This previously required importing the :mod:`gc` module and calling - Python functions in it, which is cumbersome from C code. + These functions allow to activate, deactivate and query the state of the garbage collector from C code without + having to import the :mod:`gc` module. Porting to Python 3.10 ---------------------- From 56465a9c1b8ab8b5c4d0b203abd0881db9187aff Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 15:46:00 +0200 Subject: [PATCH 04/17] bpo-28254: Return the previous GC state from the Enable/Disable functions to make it easy for users to ('atomically') know whether they actually changed something and what state to go back to later. Also, returning an "int" may make it easier to add error handling later, if that becomes needed at some point. --- Include/objimpl.h | 4 ++-- Modules/_testcapimodule.c | 27 +++++++++++++++++++-------- Modules/gcmodule.c | 8 ++++++-- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Include/objimpl.h b/Include/objimpl.h index e5be89ebc008d6..230c46c4f7417d 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -153,8 +153,8 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); /* C equivalent of gc.collect() which ignores the state of gc.enabled. */ PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); /* C API for controlling the state of the garbage collector */ -PyAPI_FUNC(void) PyGC_Enable(void); -PyAPI_FUNC(void) PyGC_Disable(void); +PyAPI_FUNC(int) PyGC_Enable(void); +PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); /* Test if a type has a GC head */ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index a856b6739a2317..5e150e6d5ff686 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -149,20 +149,31 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) { int orig_enabled = PyGC_IsEnabled(); const char* msg = "ok"; + int old_state; - PyGC_Enable(); - msg = "enable(1)"; + old_state = PyGC_Enable(); + msg = "Enable(1)"; + if (old_state != orig_enabled) goto failed; + msg = "IsEnabled(1)"; if (!PyGC_IsEnabled()) goto failed; - PyGC_Disable(); - msg = "disable(1)"; + + old_state = PyGC_Disable(); + msg = "disable(2)"; + if (!old_state) goto failed; + msg = "IsEnabled(2)"; if (PyGC_IsEnabled()) goto failed; - PyGC_Enable(); - msg = "enable(2)"; + + old_state = PyGC_Enable(); + msg = "enable(3)"; + if (old_state) goto failed; + msg = "IsEnabled(3)"; if (!PyGC_IsEnabled()) goto failed; if (!orig_enabled) { - PyGC_Disable(); - msg = "disable(2)"; + old_state = PyGC_Disable(); + msg = "disable(4)"; + if (old_state) goto failed; + msg = "IsEnabled(4)"; if (PyGC_IsEnabled()) goto failed; } diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5e2651894a694f..5de6c5c1f863b7 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2079,18 +2079,22 @@ PyGC_Collect(void) } /* C API for controlling the state of the garbage collector */ -void +int PyGC_Enable(void) { GCState *gcstate = get_gc_state(); + int old_state = gcstate->enabled; gcstate->enabled = 1; + return old_state; } -void +int PyGC_Disable(void) { GCState *gcstate = get_gc_state(); + int old_state = gcstate->enabled; gcstate->enabled = 0; + return old_state; } int From 7b6e3203761ad1c491459101f53de58977a46de8 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 28 Apr 2021 14:47:35 +0100 Subject: [PATCH 05/17] Update Modules/_testcapimodule.c --- Modules/_testcapimodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5e150e6d5ff686..efa13dc53d1743 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -155,7 +155,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) msg = "Enable(1)"; if (old_state != orig_enabled) goto failed; msg = "IsEnabled(1)"; - if (!PyGC_IsEnabled()) goto failed; + if (!PyGC_IsEnabled()) { + goto failed; + } old_state = PyGC_Disable(); msg = "disable(2)"; From b7e4ee3deb336625f692893f4df457e8569f7e21 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 28 Apr 2021 14:47:40 +0100 Subject: [PATCH 06/17] Update Modules/_testcapimodule.c --- Modules/_testcapimodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index efa13dc53d1743..0c7d263a32bd8d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -169,7 +169,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) msg = "enable(3)"; if (old_state) goto failed; msg = "IsEnabled(3)"; - if (!PyGC_IsEnabled()) goto failed; + if (!PyGC_IsEnabled()) { + goto failed; + } if (!orig_enabled) { old_state = PyGC_Disable(); From 4e11560c8faa84e36529410fed1d645c2db064e2 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 28 Apr 2021 14:47:45 +0100 Subject: [PATCH 07/17] Update Modules/_testcapimodule.c --- Modules/_testcapimodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 0c7d263a32bd8d..d0ec318f3fceb0 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -163,7 +163,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) msg = "disable(2)"; if (!old_state) goto failed; msg = "IsEnabled(2)"; - if (PyGC_IsEnabled()) goto failed; + if (PyGC_IsEnabled()) { + goto failed; + } old_state = PyGC_Enable(); msg = "enable(3)"; From e5f0077f7575d10fe91934ac01441fd9d6b47868 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 15:51:15 +0200 Subject: [PATCH 08/17] bpo-28254: Formatting. --- Modules/_testcapimodule.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index d0ec318f3fceb0..26ebacba642a4f 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -153,7 +153,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) old_state = PyGC_Enable(); msg = "Enable(1)"; - if (old_state != orig_enabled) goto failed; + if (old_state != orig_enabled) { + goto failed; + } msg = "IsEnabled(1)"; if (!PyGC_IsEnabled()) { goto failed; @@ -161,7 +163,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) old_state = PyGC_Disable(); msg = "disable(2)"; - if (!old_state) goto failed; + if (!old_state) { + goto failed; + } msg = "IsEnabled(2)"; if (PyGC_IsEnabled()) { goto failed; @@ -169,7 +173,9 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) old_state = PyGC_Enable(); msg = "enable(3)"; - if (old_state) goto failed; + if (old_state) { + goto failed; + } msg = "IsEnabled(3)"; if (!PyGC_IsEnabled()) { goto failed; @@ -178,9 +184,13 @@ test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) if (!orig_enabled) { old_state = PyGC_Disable(); msg = "disable(4)"; - if (old_state) goto failed; + if (old_state) { + goto failed; + } msg = "IsEnabled(4)"; - if (PyGC_IsEnabled()) goto failed; + if (PyGC_IsEnabled()) { + goto failed; + } } Py_RETURN_NONE; From c64aa42a341592a56ec282beaaf37cffcd126028 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 16:26:46 +0200 Subject: [PATCH 09/17] bpo-28254: Move new functions to a better place (not cutting into the gc.collect() implementation). --- Modules/gcmodule.c | 52 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5de6c5c1f863b7..e5e5aa3287b0d6 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2050,6 +2050,32 @@ PyInit_gc(void) return PyModuleDef_Init(&gcmodule); } +/* C API for controlling the state of the garbage collector */ +int +PyGC_Enable(void) +{ + GCState *gcstate = get_gc_state(); + int old_state = gcstate->enabled; + gcstate->enabled = 1; + return old_state; +} + +int +PyGC_Disable(void) +{ + GCState *gcstate = get_gc_state(); + int old_state = gcstate->enabled; + gcstate->enabled = 0; + return old_state; +} + +int +PyGC_IsEnabled(void) +{ + GCState *gcstate = get_gc_state(); + return gcstate->enabled; +} + /* Public API to invoke gc.collect() from C */ Py_ssize_t PyGC_Collect(void) @@ -2078,32 +2104,6 @@ PyGC_Collect(void) return n; } -/* C API for controlling the state of the garbage collector */ -int -PyGC_Enable(void) -{ - GCState *gcstate = get_gc_state(); - int old_state = gcstate->enabled; - gcstate->enabled = 1; - return old_state; -} - -int -PyGC_Disable(void) -{ - GCState *gcstate = get_gc_state(); - int old_state = gcstate->enabled; - gcstate->enabled = 0; - return old_state; -} - -int -PyGC_IsEnabled(void) -{ - GCState *gcstate = get_gc_state(); - return gcstate->enabled; -} - Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate) { From cbee918d35cc8121d1ef2c9acc470d2d72b3c06b Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 16:28:55 +0200 Subject: [PATCH 10/17] Remove an incorrect part of a comment: PyGC_Collect() actually does nothing if GC is disabled. --- Include/objimpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/objimpl.h b/Include/objimpl.h index 230c46c4f7417d..689c42b7475c89 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -150,7 +150,7 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); * ========================== */ -/* C equivalent of gc.collect() which ignores the state of gc.enabled. */ +/* C equivalent of gc.collect(). */ PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); /* C API for controlling the state of the garbage collector */ PyAPI_FUNC(int) PyGC_Enable(void); From 0f7e6088301597afccee6b5a1d61f04774c4ae11 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 16:43:52 +0200 Subject: [PATCH 11/17] bpo-28254: Add documentation for the PyGC_*() functions. --- Doc/c-api/gcsupport.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index eee114c19d5904..40c29db5c63b7f 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -173,3 +173,43 @@ if the object is immutable. this method (don't just call :c:func:`Py_DECREF` on a reference). The collector will call this method if it detects that this object is involved in a reference cycle. + + +Controlling the Garbage Collector State +--------------------------------------- + +The C-API provides the following functions for controlling +garbage collection runs. + +.. c:function:: Py_ssize_t PyGC_Collect(void) + + Performs a garbage collection, if the garbage collector is enabled. + Returns the number of collected + uncollectable objects. + If the garbage collector is disabled or already running, + returns ``0`` immediately. + Errors during garbage collection are ignored and printed. + This function does not raise exceptions. + + +.. c:function:: int PyGC_Enable(void) + + Enable the garbage collector. + Returns the previous state, 0 for disabled and 1 for enabled. + +.. versionchanged:: 3.10 + + +.. c:function:: int PyGC_Disable(void) + + Disable the garbage collector. + Returns the previous state, 0 for disabled and 1 for enabled. + +.. versionchanged:: 3.10 + + +.. c:function:: int PyGC_IsEnabled(void) + + Queries the state of the garbage collector. + Returns the current state, 0 for disabled and 1 for enabled. + +.. versionchanged:: 3.10 From 80c36257a8749b03607a291fa12322e2c4802292 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 16:50:48 +0200 Subject: [PATCH 12/17] bpo-28254: Add new PyGC_*() functions to the stable ABI list. --- Doc/data/stable_abi.dat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index cdc7160250243b..491a5fbb96f5a5 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -268,6 +268,9 @@ PyFrame_GetLineNumber PyFrozenSet_New PyFrozenSet_Type PyGC_Collect +PyGC_Disable +PyGC_Enable +PyGC_IsEnabled PyGILState_Ensure PyGILState_GetThisThreadState PyGILState_Release From 25fb2aa9b341837030eca9aa3d3597d28c183186 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 17:31:30 +0200 Subject: [PATCH 13/17] bpo-28254: Apply suggestions from doc review. --- Doc/c-api/gcsupport.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 40c29db5c63b7f..861f6d92ffc5c8 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -183,11 +183,12 @@ garbage collection runs. .. c:function:: Py_ssize_t PyGC_Collect(void) - Performs a garbage collection, if the garbage collector is enabled. - Returns the number of collected + uncollectable objects. - If the garbage collector is disabled or already running, + Perform a full garbage collection, if the garbage collector is enabled. + Returns the number of collected + unreachable objects which cannot + be collected. + If the garbage collector is disabled or already collecting, returns ``0`` immediately. - Errors during garbage collection are ignored and printed. + Errors during garbage collection are passed to :data:`sys.unraisablehook`. This function does not raise exceptions. @@ -209,7 +210,7 @@ garbage collection runs. .. c:function:: int PyGC_IsEnabled(void) - Queries the state of the garbage collector. + Query the state of the garbage collector. Returns the current state, 0 for disabled and 1 for enabled. .. versionchanged:: 3.10 From 10ad9294aeeb4aeb01050ea976340867b58f9740 Mon Sep 17 00:00:00 2001 From: scoder Date: Wed, 28 Apr 2021 17:42:36 +0200 Subject: [PATCH 14/17] Apply suggestions from doc review Co-authored-by: Victor Stinner --- Doc/c-api/gcsupport.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 861f6d92ffc5c8..b426d7987fd62e 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -194,7 +194,7 @@ garbage collection runs. .. c:function:: int PyGC_Enable(void) - Enable the garbage collector. + Enable the garbage collector: similar to :func:`gc.enable`. Returns the previous state, 0 for disabled and 1 for enabled. .. versionchanged:: 3.10 @@ -202,7 +202,7 @@ garbage collection runs. .. c:function:: int PyGC_Disable(void) - Disable the garbage collector. + Disable the garbage collector: similar to :func:`gc.disable`. Returns the previous state, 0 for disabled and 1 for enabled. .. versionchanged:: 3.10 @@ -210,7 +210,7 @@ garbage collection runs. .. c:function:: int PyGC_IsEnabled(void) - Query the state of the garbage collector. + Query the state of the garbage collector: similar to :func:`gc.isenabled`. Returns the current state, 0 for disabled and 1 for enabled. .. versionchanged:: 3.10 From 1ffe9371603f676fa883ffe7a6419dccd1357200 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 17:48:26 +0200 Subject: [PATCH 15/17] Add a word on how PyGC_Collect() and gc.collect() differ. --- Doc/c-api/gcsupport.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index b426d7987fd62e..e0ef475b4dc9c5 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -184,6 +184,8 @@ garbage collection runs. .. c:function:: Py_ssize_t PyGC_Collect(void) Perform a full garbage collection, if the garbage collector is enabled. + (Note that :func:`gc.collect` runs it unconditionally.) + Returns the number of collected + unreachable objects which cannot be collected. If the garbage collector is disabled or already collecting, From d517665ed8953786e3d8c45cee2c03e9e1e2d203 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 17:49:56 +0200 Subject: [PATCH 16/17] Fix version marker. --- Doc/c-api/gcsupport.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index e0ef475b4dc9c5..23aebf98e0736a 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -199,7 +199,7 @@ garbage collection runs. Enable the garbage collector: similar to :func:`gc.enable`. Returns the previous state, 0 for disabled and 1 for enabled. -.. versionchanged:: 3.10 +.. versionadded:: 3.10 .. c:function:: int PyGC_Disable(void) @@ -207,7 +207,7 @@ garbage collection runs. Disable the garbage collector: similar to :func:`gc.disable`. Returns the previous state, 0 for disabled and 1 for enabled. -.. versionchanged:: 3.10 +.. versionadded:: 3.10 .. c:function:: int PyGC_IsEnabled(void) @@ -215,4 +215,4 @@ garbage collection runs. Query the state of the garbage collector: similar to :func:`gc.isenabled`. Returns the current state, 0 for disabled and 1 for enabled. -.. versionchanged:: 3.10 +.. versionadded:: 3.10 From 84fb2afd755945720d581908dac5309461cc72e8 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 28 Apr 2021 17:51:46 +0200 Subject: [PATCH 17/17] Fix version marker (II). --- Doc/c-api/gcsupport.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 23aebf98e0736a..55ed9d4f7fad48 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -199,7 +199,7 @@ garbage collection runs. Enable the garbage collector: similar to :func:`gc.enable`. Returns the previous state, 0 for disabled and 1 for enabled. -.. versionadded:: 3.10 + .. versionadded:: 3.10 .. c:function:: int PyGC_Disable(void) @@ -207,7 +207,7 @@ garbage collection runs. Disable the garbage collector: similar to :func:`gc.disable`. Returns the previous state, 0 for disabled and 1 for enabled. -.. versionadded:: 3.10 + .. versionadded:: 3.10 .. c:function:: int PyGC_IsEnabled(void) @@ -215,4 +215,4 @@ garbage collection runs. Query the state of the garbage collector: similar to :func:`gc.isenabled`. Returns the current state, 0 for disabled and 1 for enabled. -.. versionadded:: 3.10 + .. versionadded:: 3.10