Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
bpo-28254: Add a C-API for controlling the state of the garbage collector#25687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
6229a31bfbadb9f41d26956465a97b6e320b7e4ee34e11560e5f0077c64aa42cbee9180f7e60880c362525fb2aa10ad9291ffe937d51766584fb2afFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -173,3 +173,46 @@ 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) | ||
| 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, | ||
| returns ``0`` immediately. | ||
| Errors during garbage collection are passed to :data:`sys.unraisablehook`. | ||
| This function does not raise exceptions. | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pablogsal: Do we want to document that it's safe to call this function with an exception raised, and that the exception is saved and then restored? | ||
| .. c:function:: int PyGC_Enable(void) | ||
| Enable the garbage collector: similar to :func:`gc.enable`. | ||
| Returns the previous state, 0 for disabled and 1 for enabled. | ||
| .. versionadded:: 3.10 | ||
| .. c:function:: int PyGC_Disable(void) | ||
| Disable the garbage collector: similar to :func:`gc.disable`. | ||
| Returns the previous state, 0 for disabled and 1 for enabled. | ||
| .. versionadded:: 3.10 | ||
| .. c:function:: int PyGC_IsEnabled(void) | ||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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()`. | ||
scoder marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 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 | ||
| ---------------------- | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Add new C-API functions to control the state of the garbage collector: | ||
scoder marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| :c:func:`PyGC_Enable()`, :c:func:`PyGC_Disable()`, :c:func:`PyGC_IsEnabled()`, | ||
| corresponding to the functions in the :mod:`gc` module. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -144,6 +144,67 @@ 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"; | ||
| int old_state; | ||
| old_state = PyGC_Enable(); | ||
| msg = "Enable(1)"; | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bugs are unlikely. IMO using assert() is good enough for _testcapi tests. You can leave the code as it is ;-) See for example test_refcount_funcs() which uses assert(). ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking that assertions can be compiled out, which is decidedly not intended here. Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general yes, but _testcapimodule.c starts with: ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good to know! I'd keep the test as it is though. It doesn't really hurt, I think. | ||
| if (old_state != orig_enabled) { | ||
| goto failed; | ||
| } | ||
| msg = "IsEnabled(1)"; | ||
| if (!PyGC_IsEnabled()) { | ||
| goto failed; | ||
| } | ||
| old_state = PyGC_Disable(); | ||
| msg = "disable(2)"; | ||
| if (!old_state) { | ||
| goto failed; | ||
| } | ||
| msg = "IsEnabled(2)"; | ||
| if (PyGC_IsEnabled()) { | ||
| goto failed; | ||
| } | ||
| old_state = PyGC_Enable(); | ||
| msg = "enable(3)"; | ||
| if (old_state) { | ||
| goto failed; | ||
| } | ||
| msg = "IsEnabled(3)"; | ||
| if (!PyGC_IsEnabled()) { | ||
| goto failed; | ||
| } | ||
| if (!orig_enabled) { | ||
| old_state = PyGC_Disable(); | ||
| msg = "disable(4)"; | ||
| if (old_state) { | ||
| goto failed; | ||
| } | ||
| msg = "IsEnabled(4)"; | ||
| 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 +5605,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}, | ||
Uh oh!
There was an error while loading. Please reload this page.