bpo-39947: Hide implementation detail of trashcan macros (GH-18971)
Py_TRASHCAN_BEGIN_CONDITION and Py_TRASHCAN_END macro no longer
access PyThreadState attributes, but call new private
_PyTrash_begin() and _PyTrash_end() functions which hide
implementation details.
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 4600f94..45da752 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -385,11 +385,6 @@
*/
PyAPI_DATA(int) _Py_SwappedOp[];
-/* This is the old private API, invoked by the macros before 3.2.4.
- Kept for binary compatibility of extensions using the stable ABI. */
-PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*);
-PyAPI_FUNC(void) _PyTrash_destroy_chain(void);
-
PyAPI_FUNC(void)
_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
size_t sizeof_block);
@@ -507,10 +502,23 @@
passed as second argument to Py_TRASHCAN_BEGIN().
*/
-/* The new thread-safe private API, invoked by the macros below. */
+/* This is the old private API, invoked by the macros before 3.2.4.
+ Kept for binary compatibility of extensions using the stable ABI. */
+PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*);
+PyAPI_FUNC(void) _PyTrash_destroy_chain(void);
+
+/* This is the old private API, invoked by the macros before 3.9.
+ Kept for binary compatibility of extensions using the stable ABI. */
PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*);
PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
+/* Forward declarations for PyThreadState */
+struct _ts;
+
+/* Python 3.9 private API, invoked by the macros below. */
+PyAPI_FUNC(int) _PyTrash_begin(struct _ts *tstate, PyObject *op);
+PyAPI_FUNC(void) _PyTrash_end(struct _ts *tstate);
+
#define PyTrash_UNWIND_LEVEL 50
#define Py_TRASHCAN_BEGIN_CONDITION(op, cond) \
@@ -520,24 +528,19 @@
* is run normally without involving the trashcan */ \
if (cond) { \
_tstate = PyThreadState_GET(); \
- if (_tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) { \
- /* Store the object (to be deallocated later) and jump past \
- * Py_TRASHCAN_END, skipping the body of the deallocator */ \
- _PyTrash_thread_deposit_object(_PyObject_CAST(op)); \
+ if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \
break; \
} \
- ++_tstate->trash_delete_nesting; \
}
/* The body of the deallocator is here. */
#define Py_TRASHCAN_END \
if (_tstate) { \
- --_tstate->trash_delete_nesting; \
- if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \
- _PyTrash_thread_destroy_chain(); \
+ _PyTrash_end(_tstate); \
} \
} while (0);
-#define Py_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN_CONDITION(op, \
+#define Py_TRASHCAN_BEGIN(op, dealloc) \
+ Py_TRASHCAN_BEGIN_CONDITION(op, \
Py_TYPE(op)->tp_dealloc == (destructor)(dealloc))
/* For backwards compatibility, these macros enable the trashcan