-
-
Notifications
You must be signed in to change notification settings - Fork 35.1k
gh-75537: Add gc.ensure_disabled() context manager #154999
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
b527c01
83d9729
cab16ea
60631ff
5a55da3
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 |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Add :func:`gc.ensure_disabled` context manager to temporarily disable | ||
| the garbage collector. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,6 +65,76 @@ gc_isenabled_impl(PyObject *module) | |
| return PyGC_IsEnabled(); | ||
| } | ||
|
|
||
|
|
||
| /* Context manager to temporarily disable the garbage collector. */ | ||
|
|
||
| typedef struct { | ||
| PyObject_HEAD | ||
| int old_state; | ||
| } _gc_ensure_disabled_state; | ||
|
|
||
| static void | ||
| _gc_ensure_disabled_dealloc(PyObject *self) | ||
| { | ||
| PyObject_Free(self); | ||
| } | ||
|
|
||
| static PyObject * | ||
| _gc_ensure_disabled_enter(PyObject *self, PyObject *Py_UNUSED(args)) | ||
| { | ||
| Py_RETURN_NONE; | ||
| } | ||
|
|
||
| static PyObject * | ||
| _gc_ensure_disabled_exit(PyObject *self, PyObject *args) | ||
| { | ||
| _gc_ensure_disabled_state *s = (_gc_ensure_disabled_state *)self; | ||
| if (s->old_state) { | ||
| PyGC_Enable(); | ||
| } | ||
| Py_RETURN_NONE; | ||
| } | ||
|
|
||
| static PyMethodDef _gc_ensure_disabled_methods[] = { | ||
| {"__enter__", _gc_ensure_disabled_enter, METH_NOARGS, NULL}, | ||
|
SakshamKapoor2911 marked this conversation as resolved.
|
||
| {"__exit__", _gc_ensure_disabled_exit, METH_VARARGS, NULL}, | ||
| {NULL, NULL, 0, NULL} | ||
| }; | ||
|
|
||
| static PyTypeObject _GCEnsureDisabled_Type = { | ||
| PyVarObject_HEAD_INIT(NULL, 0) | ||
| .tp_name = "gc._ensure_disabled", | ||
| .tp_basicsize = sizeof(_gc_ensure_disabled_state), | ||
| .tp_dealloc = _gc_ensure_disabled_dealloc, | ||
| .tp_flags = Py_TPFLAGS_DEFAULT, | ||
| .tp_methods = _gc_ensure_disabled_methods, | ||
| }; | ||
|
|
||
|
|
||
| PyDoc_STRVAR(gc_ensure_disabled__doc__, | ||
| "ensure_disabled() -> context manager\n" | ||
|
Contributor
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.
Author
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. That's correct, and consistent with all Python context managers. threading.Lock().acquire() without
Author
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. @maurycy Do you think this is a reasonable tradeoff, or would you suggest I made modifications to prevent this? |
||
| "\n" | ||
| "Context manager to temporarily disable the garbage collector.\n" | ||
| "\n" | ||
| "At the start of the block the garbage collector is disabled.\n" | ||
| "On exit, it is restored to its previous state.\n" | ||
| "\n" | ||
| "Example:\n" | ||
| " with gc.ensure_disabled():\n" | ||
| " ... # GC is disabled during this block\n"); | ||
|
|
||
| static PyObject * | ||
| gc_ensure_disabled(PyObject *module, PyObject *Py_UNUSED(args)) | ||
| { | ||
| _gc_ensure_disabled_state *ctx = PyObject_New( | ||
| _gc_ensure_disabled_state, &_GCEnsureDisabled_Type); | ||
| if (ctx == NULL) { | ||
| return NULL; | ||
| } | ||
| ctx->old_state = PyGC_Disable(); | ||
| return (PyObject *)ctx; | ||
| } | ||
|
|
||
| /*[clinic input] | ||
| gc.collect -> Py_ssize_t | ||
|
|
||
|
|
@@ -521,7 +591,8 @@ PyDoc_STRVAR(gc__doc__, | |
| "get_referents() -- Return the list of objects that an object refers to.\n" | ||
| "freeze() -- Freeze all tracked objects and ignore them for future collections.\n" | ||
| "unfreeze() -- Unfreeze all objects in the permanent generation.\n" | ||
| "get_freeze_count() -- Return the number of objects in the permanent generation.\n"); | ||
| "get_freeze_count() -- Return the number of objects in the permanent generation.\n" | ||
| "ensure_disabled() -- Context manager to temporarily disable the garbage collector.\n"); | ||
|
|
||
| static PyMethodDef GcMethods[] = { | ||
| GC_ENABLE_METHODDEF | ||
|
|
@@ -542,6 +613,7 @@ static PyMethodDef GcMethods[] = { | |
| GC_FREEZE_METHODDEF | ||
| GC_UNFREEZE_METHODDEF | ||
| GC_GET_FREEZE_COUNT_METHODDEF | ||
| {"ensure_disabled", gc_ensure_disabled, METH_NOARGS, gc_ensure_disabled__doc__}, | ||
| {NULL, NULL} /* Sentinel */ | ||
| }; | ||
|
|
||
|
|
@@ -550,6 +622,10 @@ gcmodule_exec(PyObject *module) | |
| { | ||
| GCState *gcstate = get_gc_state(); | ||
|
|
||
| if (PyType_Ready(&_GCEnsureDisabled_Type) < 0) { | ||
| return -1; | ||
| } | ||
|
|
||
| /* garbage and callbacks are initialized by _PyGC_Init() early in | ||
| * interpreter lifecycle. */ | ||
| assert(gcstate->garbage != NULL); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.