classification
Title: Add C API for gc.enable, gc.disable, and gc.isenabled
Type: resource usage Stage: resolved
Components: C API Versions: Python 3.10
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: da-woods, gregory.p.smith, llllllllll, petr.viktorin, scoder, vstinner
Priority: normal Keywords: patch

Created on 2016-09-23 06:21 by llllllllll, last changed 2021-04-29 13:47 by petr.viktorin. This issue is now closed.

Files
File name Uploaded Description Edit
gc-capi.patch llllllllll, 2016-09-23 06:21 review
Pull Requests
URL Status Linked Edit
PR 25687 merged scoder, 2021-04-28 13:13
PR 25693 merged vstinner, 2021-04-28 16:18
PR 25709 merged vstinner, 2021-04-29 06:44
PR 25720 merged petr.viktorin, 2021-04-29 13:19
Messages (12)
msg277245 - (view) Author: Joe Jevnik (llllllllll) * Date: 2016-09-23 06:21
I was writing an extension module that was working with weakrefs and wanted to ensure that the GC would not run for a block of code. I noticed that gc.enable/gc.disable are not exposed to C and the state of the gc is in a static variable so it cannot be mutated from an extension.

This change adds an easier way to access this functionality in the C api without going through an import or PyObject_Call.

I am wondering where to document these functions as well as PyGC_Collect. I didn't see that function anywhere in the docs (and didn't know about it) so I would like to make them more visible. My first thought was Doc/c-api/gcsupport.rst but this is not in service of supporting the GC, it is about the state of the GC itself. If that seems like a decent place I could add a small section at the bottom about interacting with the GC and document these new functions and PyGC_Collect.

I'm sorry if this is exposed elsewhere. If it is I can try to add some links to i
msg277295 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-09-23 19:18
What use case do you have that warrants a C API expansion rather than just using PyObject_Call?  I don't recall this ever having been requested which suggests that it is either unnecessary or that people fear opening a can of worms.
msg277557 - (view) Author: Joe Jevnik (llllllllll) * Date: 2016-09-27 22:24
I definitely could have used PyImport_Import and PyObject_Call to accomplish this task; however, when I looked at at the implementation of these functions it seemed like a lot of overhead and book keeping just to set a boolean. Since I was already in a C extension it would be nicer to not need to worry about PyObjects and ref counts just to set this value so I thought it would be nice to expose these small functions to users. Since this is equivalent to gc.enable or gc.disable I don't think there is a deep can of worms here. The only difference in the implementation is that it doesn't return None. There is already PyGC_Collect, so I figured these were just omitted because no one thought to add them. I don't have a burning desire to get this in, I just thought it would be a nice to have.
msg277569 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-09-28 00:51
>  I don't have a burning desire to get this in, 
> I just thought it would be a nice to have.

In that case, I think we should decline.
msg358330 - (view) Author: Sergei Lebedev (superbobry) * Date: 2019-12-13 13:24
I know this patch has already been rejected, but I wanted to give another potential use-case for accessing GC status from C: JIT compilers.

Imagine a JIT compiler which uses alternative storage for instance attributes. In order to maintain correctness, it should "materialize" the stored attributes whenever __dict__ (or rather a pointer to __dict__) is accessed. In this context materialization means something like:

    __dict__ = {}
    for key, value in zip(keys, values):
        __dict__[key] = value

Now, what if a __dict__ is accessed during a GC collection (which is possible: collect->deduce_unreachable->subtract_refs->subtype_traverse via tp_traverse)? The JIT compiler should be able to detect such calls and avoid allocating anything:

    if collecting:
        return

    __dict__ = {}
    # ...

This is possible to implement in pure Python using gc.isenabled and gc.callbacks, but there is no existing API to do that in C.

Does this sounds convincing enough to motivate adding

int PyGC_IsEnabled(void)
int PyGC_IsCollecting(void)

to the C API?
msg391274 - (view) Author: (da-woods) * Date: 2021-04-17 07:38
Cython currently does an elaborate process of importing the GC module and loading the "isenabled", "enable" and "disable" attributes each time it creates a cdef type

https://github.com/cython/cython/blob/master/Cython/Utility/ExtensionTypes.c#L73-L107

Admittedly that's partly because it's abusing the Py_TPFLAGS_HEAPTYPE to allow multiple inheritance where Python doesn't really allow it.

But the up-shot is that Cython definite has a use-case for doing this directly in the C API, and would use these functions if provided.
msg391291 - (view) Author: Stefan Behnel (scoder) * (Python committer) Date: 2021-04-17 16:21
I support that there should be a simple way to do this from C. The way via importing the "gc" module and then looking up an attribute (possibly building a Unicode string) and calling a function in it involves several operations that can take some time and require useless error handling since each of them will practically never fail but may. An operation as simple as changing the GC status shouldn't require that.

A use case is building large data structures, or critical rearrangements of data structures that involve object operations that might trigger a GC run, maybe even including temporarily invalid object states and graphs. When larger data structures are involved but no collectable cycles, then the GC will probably not do anything useful except slowing down the creation process and/or running arbitrary code in between.

I consider the need to disable garbage collection in critical sections of C code similar to locking and GIL handling. It isn't quite the same as locking, since other code can enable it again when it runs, which isn't the case for a lock, but especially in that case, being able to detect quickly whether it was re-enabled when my own code gains back control seems beneficial. Having to call a Python function for that and taking care of the object result is way too much overhead for this case.

The fact that this is a rare request may not necessarily mean that it's rarely needed. There is certainly a bunch of C code out there that would benefit from temporarily disabling the GC in critical sections. I would imagine that people simply don't think of doing it and fail to notice any resulting slow-downs or even crashes since those often require elaborate circumstances to occur, and thus may not become visible at all in test or benchmark scenarios.

Note that the GC state is now part of the PyInterpreterState, so a patch would need to do what "gc_enable_impl" and "gc_disable_impl" do in Modules/gcmodule.c, or, rather, become their implementation to share code.
msg392195 - (view) Author: Stefan Behnel (scoder) * (Python committer) Date: 2021-04-28 13:43
I just remembered that it's usually helpful to return the previous state, so that callers know whether they need to re-enable or disable the GC when they're done. I'll add that.

Also, returning an "int" may allow us to add a "-1" error code at some point, if it turns out to become necessary.
msg392230 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-04-28 16:12
New changeset 3cc481b9de43c234889c8010e7da3af7c0f42319 by scoder in branch 'master':
bpo-28254: Add a C-API for controlling the GC state (GH-25687)
https://github.com/python/cpython/commit/3cc481b9de43c234889c8010e7da3af7c0f42319
msg392239 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-04-28 17:09
New changeset 103d5e420dd90489933ad9da8bb1d6008773384d by Victor Stinner in branch 'master':
bpo-28254: _posixsubprocess uses PyGC_Enable/PyGC_Disable (GH-25693)
https://github.com/python/cpython/commit/103d5e420dd90489933ad9da8bb1d6008773384d
msg392289 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-04-29 08:26
New changeset b1f413e6cf63a1c5704fcb47f2095ef5db8970bb by Victor Stinner in branch 'master':
bpo-28254: Cleanup test_subprocess.test_preexec_gc_module_failure() (GH-25709)
https://github.com/python/cpython/commit/b1f413e6cf63a1c5704fcb47f2095ef5db8970bb
msg392308 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-04-29 13:47
New changeset 14fc2bdfab857718429029e53ceffca456178827 by Petr Viktorin in branch 'master':
bpo-28254: Add PyGC_ functions to the stable ABI manifest (GH-25720)
https://github.com/python/cpython/commit/14fc2bdfab857718429029e53ceffca456178827
History
Date User Action Args
2021-04-29 13:47:06petr.viktorinsetmessages: + msg392308
2021-04-29 13:19:30petr.viktorinsetnosy: + petr.viktorin

pull_requests: + pull_request24411
2021-04-29 08:26:57vstinnersetmessages: + msg392289
2021-04-29 06:44:45vstinnersetpull_requests: + pull_request24398
2021-04-28 17:09:33vstinnersetmessages: + msg392239
2021-04-28 16:18:38vstinnersetpull_requests: + pull_request24383
2021-04-28 16:15:19scodersetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2021-04-28 16:12:29vstinnersetnosy: + vstinner
messages: + msg392230
2021-04-28 13:43:16scodersetmessages: + msg392195
2021-04-28 13:13:05scodersetnosy: + scoder

pull_requests: + pull_request24377
stage: needs patch -> patch review
2021-04-18 02:20:43rhettingersetnosy: - rhettinger, scoder, superbobry
2021-04-17 16:21:43scodersetstatus: closed -> open

type: resource usage
components: + C API, - Extension Modules
versions: + Python 3.10, - Python 3.7
nosy: + scoder

messages: + msg391291
resolution: rejected -> (no value)
stage: needs patch
2021-04-17 07:38:11da-woodssetnosy: + da-woods
messages: + msg391274
2019-12-13 13:24:48superbobrysetnosy: + superbobry
messages: + msg358330
2019-12-11 17:44:04gregory.p.smithsetnosy: + gregory.p.smith
2016-09-28 00:51:15rhettingersetstatus: open -> closed
resolution: rejected
messages: + msg277569
2016-09-27 22:24:19llllllllllsetmessages: + msg277557
2016-09-23 19:18:58rhettingersetnosy: + rhettinger
messages: + msg277295
2016-09-23 06:21:47llllllllllcreate