-
-
Notifications
You must be signed in to change notification settings - Fork 32k
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
Changes from all commits
6229a31
bfbadb9
f41d269
56465a9
7b6e320
b7e4ee3
4e11560
e5f0077
c64aa42
cbee918
0f7e608
80c3625
25fb2aa
10ad929
1ffe937
d517665
84fb2af
File filter
Filter by extension
Conversations
Jump to
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. | ||
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Add new C-API functions to control the state of the garbage collector: | ||
scoder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
: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)"; | ||
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(). 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. 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:
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.