From 6a6d61ca1c18e8e255c9a62d2d1102062b9378f8 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Fri, 10 Apr 2020 19:46:08 +0100 Subject: [PATCH 1/2] bpo-40241: Add PyObject_GC_IsTracked and PyObject_GC_IsFinalized to the public C-API --- Doc/c-api/gcsupport.rst | 20 +++++++++++++++++++ Doc/whatsnew/3.9.rst | 7 +++++++ Include/objimpl.h | 2 ++ .../2020-04-10-19-43-04.bpo-40241.Xm3w-1.rst | 4 ++++ Modules/_testcapimodule.c | 2 +- Modules/gcmodule.c | 20 +++++++++++++++++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C API/2020-04-10-19-43-04.bpo-40241.Xm3w-1.rst diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 924a7fd2fda4d56..0f6ae85c6cd526d 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -60,6 +60,26 @@ Constructors for container types must conform to two rules: followed by the :c:member:`~PyTypeObject.tp_traverse` handler become valid, usually near the end of the constructor. +.. c:function:: int PyObject_GC_IsTracked(PyObject *op) + + Returns 1 if the object *op* is being currently tracked by the garbage + collector and 0 otherwise. + + This function will return 0 for objects that do not have implemented support + for the garbage collector. + + .. versionadded:: 3.9 + + +.. c:function:: int PyObject_GC_IsFinalized(PyObject *op) + + Returns 1 if the object *op* has been already finalized by the garbage + collector and 0 otherwise. + + This function will return 0 for objects that do not have implemented support + for the garbage collector. + + .. versionadded:: 3.9 Similarly, the deallocator for the object must conform to a similar pair of rules: diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index e49d4264c659162..3beb721ed318e28 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -564,6 +564,13 @@ Build and C API Changes Windows. (Contributed by Zackery Spytz in :issue:`8901`.) +* Add the functions :c:func:`PyObject_GC_IsTracked` and + :c:func:`PyObject_GC_IsFinalized` to the public API to allow to query if + Python objects are being currently tracked or have been already finalized by + the garbage collector respectively. (Contributed by Pablo Galindo in + :issue:`40241`.) + + Deprecated ========== diff --git a/Include/objimpl.h b/Include/objimpl.h index 6e7549c90d21019..6276c51c0e7cd15 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -186,6 +186,8 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *); #define PyObject_GC_NewVar(type, typeobj, n) \ ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) +PyAPI_FUNC(int) PyObject_GC_IsTracked(void *); +PyAPI_FUNC(int) PyObject_GC_IsFinalized(void *); /* Utility macro to help write tp_traverse functions. * To use this macro, the tp_traverse function must name its arguments diff --git a/Misc/NEWS.d/next/C API/2020-04-10-19-43-04.bpo-40241.Xm3w-1.rst b/Misc/NEWS.d/next/C API/2020-04-10-19-43-04.bpo-40241.Xm3w-1.rst new file mode 100644 index 000000000000000..0ade4a5f30e2ee1 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-04-10-19-43-04.bpo-40241.Xm3w-1.rst @@ -0,0 +1,4 @@ +Add the functions :c:func:`PyObject_GC_IsTracked` and +:c:func:`PyObject_GC_IsFinalized` to the public API to allow to query if +Python objects are being currently tracked or have been already finalized by +the garbage collector respectively. Patch by Pablo Galindo. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3cc558689b6c189..0a30fea9e874768 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3588,7 +3588,7 @@ slot_tp_del(PyObject *self) _Py_NewReference(self); Py_SET_REFCNT(self, refcnt); } - assert(!PyType_IS_GC(Py_TYPE(self)) || _PyObject_GC_IS_TRACKED(self)); + assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased _Py_RefTotal, so we need to undo that. */ #ifdef Py_REF_DEBUG diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 1bc41fb83d8a609..f38064fa3978976 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2312,3 +2312,23 @@ PyObject_GC_Del(void *op) } PyObject_FREE(g); } + +int +PyObject_GC_IsTracked(void* op_raw) +{ + PyObject *obj = _PyObject_CAST(op_raw); + if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) { + return 1; + } + return 0; +} + +int +PyObject_GC_IsFinalized(void *op_raw) +{ + PyObject *obj = _PyObject_CAST(op_raw); + if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { + return 1; + } + return 0; +} From b1677e40e48e0ee15e92533041f9d8c7dd606174 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sat, 11 Apr 2020 00:44:17 +0100 Subject: [PATCH 2/2] fixup! bpo-40241: Add PyObject_GC_IsTracked and PyObject_GC_IsFinalized to the public C-API --- Doc/c-api/gcsupport.rst | 14 ++++++-------- Include/objimpl.h | 4 ++-- Modules/gcmodule.c | 6 ++---- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 0f6ae85c6cd526d..4cab0f544ed811b 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -62,22 +62,20 @@ Constructors for container types must conform to two rules: .. c:function:: int PyObject_GC_IsTracked(PyObject *op) - Returns 1 if the object *op* is being currently tracked by the garbage - collector and 0 otherwise. + Returns 1 if the object type of *op* implements the GC protocol and *op* is being + currently tracked by the garbage collector and 0 otherwise. - This function will return 0 for objects that do not have implemented support - for the garbage collector. + This is analogous to the Python function :func:`gc.is_tracked`. .. versionadded:: 3.9 .. c:function:: int PyObject_GC_IsFinalized(PyObject *op) - Returns 1 if the object *op* has been already finalized by the garbage - collector and 0 otherwise. + Returns 1 if the object type of *op* implements the GC protocol and *op* has been + already finalized by the garbage collector and 0 otherwise. - This function will return 0 for objects that do not have implemented support - for the garbage collector. + This is analogous to the Python function :func:`gc.is_finalized`. .. versionadded:: 3.9 diff --git a/Include/objimpl.h b/Include/objimpl.h index 6276c51c0e7cd15..030d7eee29723e3 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -186,8 +186,8 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *); #define PyObject_GC_NewVar(type, typeobj, n) \ ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) -PyAPI_FUNC(int) PyObject_GC_IsTracked(void *); -PyAPI_FUNC(int) PyObject_GC_IsFinalized(void *); +PyAPI_FUNC(int) PyObject_GC_IsTracked(PyObject *); +PyAPI_FUNC(int) PyObject_GC_IsFinalized(PyObject *); /* Utility macro to help write tp_traverse functions. * To use this macro, the tp_traverse function must name its arguments diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index f38064fa3978976..17541824761a132 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2314,9 +2314,8 @@ PyObject_GC_Del(void *op) } int -PyObject_GC_IsTracked(void* op_raw) +PyObject_GC_IsTracked(PyObject* obj) { - PyObject *obj = _PyObject_CAST(op_raw); if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) { return 1; } @@ -2324,9 +2323,8 @@ PyObject_GC_IsTracked(void* op_raw) } int -PyObject_GC_IsFinalized(void *op_raw) +PyObject_GC_IsFinalized(PyObject *obj) { - PyObject *obj = _PyObject_CAST(op_raw); if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { return 1; }