From c4a91e0588f2091ff97964135f10b276830c5a3d Mon Sep 17 00:00:00 2001 From: jbower <1978924+jbower-fb@users.noreply.github.com> Date: Tue, 7 Feb 2023 23:23:31 -0800 Subject: [PATCH 01/17] Add PyGC_VisitObjects Co-authored-by: Brett Simmers --- Include/objimpl.h | 7 ++++++ Modules/_testcapimodule.c | 48 +++++++++++++++++++++++++++++++++++++++ Modules/gcmodule.c | 14 ++++++++++++ 3 files changed, 69 insertions(+) diff --git a/Include/objimpl.h b/Include/objimpl.h index dde8df34835328..c946b56a52374f 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -157,6 +157,13 @@ PyAPI_FUNC(int) PyGC_Enable(void); PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); +/* Visit all live GC-capable objects, similar to gc.get_objects(None). + * + * Users should avoid allocating or deallocating objects on the Python heap in + * the callback. */ +typedef void (*gcvisitobjects_t)(PyObject*, void*); +PyAPI_FUNC(void) PyGC_VisitObjects(gcvisitobjects_t callback, void* arg); + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 0d8d1d73fb2390..45dd4d956404e3 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3517,6 +3517,53 @@ err_restore(PyObject *self, PyObject *args) { return NULL; } +struct gc_visit_state { + PyObject *target; + int found; +}; + +static void +gc_visit_callback(PyObject *obj, void* arg) { + struct gc_visit_state *state = (struct gc_visit_state *)arg; + if (obj == state->target) { + state->found = 1; + } +} + +static PyObject * +test_gc_visit_objects(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { + /* Basic sanity test: does it find objects as appropriate? */ + PyObject *obj; + struct gc_visit_state state; + + obj = PyList_New(0); + if (obj == NULL) { + goto error; + } + state.target = obj; + state.found = 0; + + PyGC_VisitObjects(gc_visit_callback, &state); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects: Didn't find live list"); + goto error; + } + + int error = 0; + goto done; +error: + error = 1; +done: + Py_XDECREF(obj); + if (error) { + return NULL; + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3671,6 +3718,7 @@ static PyMethodDef TestMethods[] = { {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"err_set_raised", err_set_raised, METH_O, NULL}, {"err_restore", err_restore, METH_VARARGS, NULL}, + {"test_gc_visit_objects", test_gc_visit_objects, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5879c5e11fe14a..a2b98662665b70 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2401,3 +2401,17 @@ PyObject_GC_IsFinalized(PyObject *obj) } return 0; } + +void +PyGC_VisitObjects(gcvisitobjects_t callback, void *arg) { + size_t i; + GCState* gcstate = get_gc_state(); + for (i = 0; i < NUM_GENERATIONS; i++) { + PyGC_Head *gc_list, *gc; + gc_list = GEN_HEAD(gcstate, i); + for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { + PyObject *op = FROM_GC(gc); + callback(op, arg); + } + } +} From 57edf6d12f79f01768e49022112d1b4e9dd6da2b Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 18 Feb 2023 00:55:15 +0000 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst new file mode 100644 index 00000000000000..4e19eb2bcc8815 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst @@ -0,0 +1 @@ +Add a new C-API function for iterating over GC'able objects using a callback: ``PyGC_VisitObjects``. From 447bb538a3e1f9c20cdf68309b60adbc534c092f Mon Sep 17 00:00:00 2001 From: jbower <1978924+jbower-fb@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:23:06 -0800 Subject: [PATCH 03/17] Remove from Limited API --- Include/objimpl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Include/objimpl.h b/Include/objimpl.h index c946b56a52374f..03a5ce6d41c735 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -157,12 +157,15 @@ PyAPI_FUNC(int) PyGC_Enable(void); PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); + +#if !defined(Py_LIMITED_API) /* Visit all live GC-capable objects, similar to gc.get_objects(None). * * Users should avoid allocating or deallocating objects on the Python heap in * the callback. */ typedef void (*gcvisitobjects_t)(PyObject*, void*); PyAPI_FUNC(void) PyGC_VisitObjects(gcvisitobjects_t callback, void* arg); +#endif /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) From d34a900e1e1a5ac18f2392579ca9c345815d0506 Mon Sep 17 00:00:00 2001 From: jbower <1978924+jbower-fb@users.noreply.github.com> Date: Wed, 22 Feb 2023 20:14:19 -0800 Subject: [PATCH 04/17] Updated to "unstable" API, protect against GC and current object deletion, add ability to terminate iteration early with test. --- Include/objimpl.h | 19 ++++++++++++----- Modules/_testcapimodule.c | 44 ++++++++++++++++++++++++++++++--------- Modules/gcmodule.c | 13 ++++++++++-- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Include/objimpl.h b/Include/objimpl.h index 03a5ce6d41c735..ef871c5ea93ebe 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -159,12 +159,21 @@ PyAPI_FUNC(int) PyGC_IsEnabled(void); #if !defined(Py_LIMITED_API) -/* Visit all live GC-capable objects, similar to gc.get_objects(None). +/* Visit all live GC-capable objects, similar to gc.get_objects(None). The + * supplied callback is called on every such object with the void* arg set + * to the supplied arg. Returning 0 from the callback ends iteration, returning + * 1 allows iteration to continue. Returning any other value may result in + * undefined behaviour. * - * Users should avoid allocating or deallocating objects on the Python heap in - * the callback. */ -typedef void (*gcvisitobjects_t)(PyObject*, void*); -PyAPI_FUNC(void) PyGC_VisitObjects(gcvisitobjects_t callback, void* arg); + * If new objects are (de)allocated by the callback it is undefined if they + * will be visited. + + * Garbage collection is disabled during operation. Explicitly running a + * collection in the callback may lead to undefined behaviour e.g. visiting the + * same objects multiple times or not at all. + */ +typedef int (*gcvisitobjects_t)(PyObject*, void*); +PyAPI_FUNC(void) PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void* arg); #endif /* Test if a type has a GC head */ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 45dd4d956404e3..f45302e6d55ecd 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3517,24 +3517,25 @@ err_restore(PyObject *self, PyObject *args) { return NULL; } -struct gc_visit_state { +struct gc_visit_state_basic { PyObject *target; int found; }; -static void -gc_visit_callback(PyObject *obj, void* arg) { - struct gc_visit_state *state = (struct gc_visit_state *)arg; +static int +gc_visit_callback_basic(PyObject *obj, void* arg) { + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; if (obj == state->target) { state->found = 1; + return 0; } + return 1; } static PyObject * -test_gc_visit_objects(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { - /* Basic sanity test: does it find objects as appropriate? */ +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { PyObject *obj; - struct gc_visit_state state; + struct gc_visit_state_basic state; obj = PyList_New(0); if (obj == NULL) { @@ -3543,11 +3544,11 @@ test_gc_visit_objects(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { state.target = obj; state.found = 0; - PyGC_VisitObjects(gc_visit_callback, &state); + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); if (!state.found) { PyErr_SetString( PyExc_AssertionError, - "test_gc_visit_objects: Didn't find live list"); + "test_gc_visit_objects_basic: Didn't find live list"); goto error; } @@ -3563,6 +3564,28 @@ test_gc_visit_objects(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { Py_RETURN_NONE; } +static int +gc_visit_callback_exit_early(PyObject *obj, void* arg) { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); @@ -3718,7 +3741,8 @@ static PyMethodDef TestMethods[] = { {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"err_set_raised", err_set_raised, METH_O, NULL}, {"err_restore", err_restore, METH_VARARGS, NULL}, - {"test_gc_visit_objects", test_gc_visit_objects, METH_NOARGS, NULL}, + {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, + {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index a2b98662665b70..92d27fa15f1d84 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2403,15 +2403,24 @@ PyObject_GC_IsFinalized(PyObject *obj) } void -PyGC_VisitObjects(gcvisitobjects_t callback, void *arg) { +PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) { size_t i; GCState* gcstate = get_gc_state(); + int origenstate = gcstate->enabled; + gcstate->enabled = 0; for (i = 0; i < NUM_GENERATIONS; i++) { PyGC_Head *gc_list, *gc; gc_list = GEN_HEAD(gcstate, i); for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { PyObject *op = FROM_GC(gc); - callback(op, arg); + Py_INCREF(op); + int res = callback(op, arg); + Py_DECREF(op); + if (!res) { + goto done; + } } } +done:; + gcstate->enabled = origenstate; } From 9b0c461f1fad04bcbe44ffce1a023928b9cb875a Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:53:55 -0800 Subject: [PATCH 05/17] Fix formatting in Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index f45302e6d55ecd..a64cdf9c0caffe 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3523,7 +3523,8 @@ struct gc_visit_state_basic { }; static int -gc_visit_callback_basic(PyObject *obj, void* arg) { +gc_visit_callback_basic(PyObject *obj, void *arg) +{ struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; if (obj == state->target) { state->found = 1; From 29f7f8883fcaf4c0f5f451c18a6243c34eac5b33 Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:54:08 -0800 Subject: [PATCH 06/17] Fix formatting in Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index a64cdf9c0caffe..3707fe4cbe04f2 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3534,7 +3534,8 @@ gc_visit_callback_basic(PyObject *obj, void *arg) } static PyObject * -test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) +{ PyObject *obj; struct gc_visit_state_basic state; From e16f1e3eecb9ddf5f6edfcc7589a073891ed4419 Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:54:32 -0800 Subject: [PATCH 07/17] Fix formatting in Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3707fe4cbe04f2..0e86a8e5ba7077 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3567,7 +3567,8 @@ test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignor } static int -gc_visit_callback_exit_early(PyObject *obj, void* arg) { +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { int *visited_i = (int *)arg; (*visited_i)++; if (*visited_i == 2) { From 024ee30262775e87213400759990d2895defc0c3 Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:55:13 -0800 Subject: [PATCH 08/17] Fix formatting in Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 0e86a8e5ba7077..0a66026ffcdf12 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3578,7 +3578,8 @@ gc_visit_callback_exit_early(PyObject *obj, void *arg) } static PyObject * -test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) +{ int visited_i = 0; PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); if (visited_i != 2) { From bd65abb099e2ab8d36ec271b388117f6eea9bf5d Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:55:30 -0800 Subject: [PATCH 09/17] Fix formatting in Modules/gcmodule.c Co-authored-by: Erlend E. Aasland --- Modules/gcmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 92d27fa15f1d84..54af6532e6982f 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2403,7 +2403,8 @@ PyObject_GC_IsFinalized(PyObject *obj) } void -PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) { +PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) +{ size_t i; GCState* gcstate = get_gc_state(); int origenstate = gcstate->enabled; From f03e581550e91f3148bfa339a96702acfe82975c Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:55:47 -0800 Subject: [PATCH 10/17] Fix formatting in Modules/gcmodule.c Co-authored-by: Erlend E. Aasland --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 54af6532e6982f..6e41da695ba522 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2406,7 +2406,7 @@ void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) { size_t i; - GCState* gcstate = get_gc_state(); + GCState *gcstate = get_gc_state(); int origenstate = gcstate->enabled; gcstate->enabled = 0; for (i = 0; i < NUM_GENERATIONS; i++) { From 16ea0d6f6052df3a41793fdac3a5d040a2b87a53 Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 11:55:57 -0800 Subject: [PATCH 11/17] Fix formatting in Modules/gcmodule.c Co-authored-by: Erlend E. Aasland --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 6e41da695ba522..d977408bdee310 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2418,7 +2418,7 @@ PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) int res = callback(op, arg); Py_DECREF(op); if (!res) { - goto done; + goto done; } } } From 369e1994da1db8bb2ece9cf9495ccf9ed07f959b Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 12:43:07 -0800 Subject: [PATCH 12/17] Simplify test in Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 0a66026ffcdf12..1f711fa57f0e79 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3541,27 +3541,18 @@ test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignor obj = PyList_New(0); if (obj == NULL) { - goto error; + return NULL; } state.target = obj; state.found = 0; - + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); if (!state.found) { PyErr_SetString( - PyExc_AssertionError, - "test_gc_visit_objects_basic: Didn't find live list"); - goto error; - } - - int error = 0; - goto done; -error: - error = 1; -done: - Py_XDECREF(obj); - if (error) { - return NULL; + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; } Py_RETURN_NONE; } From 219154af15225ed0363da3e1dff32df7d1eeb351 Mon Sep 17 00:00:00 2001 From: jbower <1978924+jbower-fb@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:21:33 -0800 Subject: [PATCH 13/17] Address minor review comments and add documentation. --- Doc/c-api/gcsupport.rst | 33 +++++++++++++++++++ ...-02-18-00-55-14.gh-issue-102013.83mrtI.rst | 2 +- Modules/gcmodule.c | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 8c90d1e8991c10..358f397ed9c9cb 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -228,3 +228,36 @@ garbage collection runs. Returns the current state, 0 for disabled and 1 for enabled. .. versionadded:: 3.10 + + +Querying Garbage Collector State +-------------------------------- + +The C-API provides the following inerface for querying information about +the garbage collector. + +.. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) + + Run supplied callback on all live GC-capable objects. + + .. warning:: + If new objects are (de)allocated by the callback it is undefined if they + will be visited. + + .. warning:: + Garbage collection is disabled during operation. Explicitly running a collection + in the callback may lead to undefined behaviour e.g. visiting the same objects + multiple times or not at all. + + .. versionadded:: 3.12 + +.. c:type:: int (*gcvisitobjects_t)(PyObject *object, void *arg) + + Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`. + ``arg`` is the same as passed to ``PyUnstable_GC_VisitObjects``. Returning ``0`` + allows iteration to continue, returning ``1`` stops further iteration. Returning any + other value has undefined behavior. + + .. versionadded:: 3.12 + + diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst index 4e19eb2bcc8815..0350237ebc7390 100644 --- a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst +++ b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst @@ -1 +1 @@ -Add a new C-API function for iterating over GC'able objects using a callback: ``PyGC_VisitObjects``. +Add a new (unstable) C-API function for iterating over GC'able objects using a callback: ``PyUnstable_VisitObjects``. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index d977408bdee310..4eaa5490b6134c 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2422,6 +2422,6 @@ PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) } } } -done:; +done: gcstate->enabled = origenstate; } From 5752f1c430f9e25d929a9ececeda781f2b4f706c Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:54:12 -0800 Subject: [PATCH 14/17] Update Doc/c-api/gcsupport.rst Co-authored-by: Erlend E. Aasland --- Doc/c-api/gcsupport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 358f397ed9c9cb..4f21c386126fe9 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -233,7 +233,7 @@ garbage collection runs. Querying Garbage Collector State -------------------------------- -The C-API provides the following inerface for querying information about +The C-API provides the following interface for querying information about the garbage collector. .. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) From 1512004ca4baed89fac7407b64703ccbdd8f9470 Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:55:05 -0800 Subject: [PATCH 15/17] Update Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c687f9e18284a6..5608705084f38b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3333,7 +3333,8 @@ gc_visit_callback_basic(PyObject *obj, void *arg) } static PyObject * -test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) { PyObject *obj; struct gc_visit_state_basic state; From 87a5b56a946b349cdf54352e48b08d5cffee325e Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:55:17 -0800 Subject: [PATCH 16/17] Update Modules/_testcapimodule.c Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5608705084f38b..4d51a39db8b053 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3369,7 +3369,8 @@ gc_visit_callback_exit_early(PyObject *obj, void *arg) } static PyObject * -test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) { int visited_i = 0; PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); From 295f7dd77e83e04617f7183e2e83d821b4526419 Mon Sep 17 00:00:00 2001 From: jbower <1978924+jbower-fb@users.noreply.github.com> Date: Sat, 11 Mar 2023 11:21:08 -0800 Subject: [PATCH 17/17] Minor doc tweaks from review --- Doc/c-api/gcsupport.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 4f21c386126fe9..cb5d64a50487fe 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -238,13 +238,13 @@ the garbage collector. .. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) - Run supplied callback on all live GC-capable objects. + Run supplied *callback* on all live GC-capable objects. *arg* is passed through to + all invocations of *callback*. .. warning:: If new objects are (de)allocated by the callback it is undefined if they will be visited. - .. warning:: Garbage collection is disabled during operation. Explicitly running a collection in the callback may lead to undefined behaviour e.g. visiting the same objects multiple times or not at all. @@ -254,9 +254,9 @@ the garbage collector. .. c:type:: int (*gcvisitobjects_t)(PyObject *object, void *arg) Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`. - ``arg`` is the same as passed to ``PyUnstable_GC_VisitObjects``. Returning ``0`` - allows iteration to continue, returning ``1`` stops further iteration. Returning any - other value has undefined behavior. + *arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``. + Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return + values are reserved for now so behavior on returning anything else is undefined. .. versionadded:: 3.12 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy