Skip to content

bpo-39947: Hide implementation detail of trashcan macros #18971

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

Merged
merged 1 commit into from
Mar 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,6 @@ PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type;
*/
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);
Expand Down Expand Up @@ -507,10 +502,23 @@ partially-deallocated object. To check this, the tp_dealloc function must be
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) \
Expand All @@ -520,24 +528,19 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
* 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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
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.
24 changes: 24 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,30 @@ _PyTrash_thread_destroy_chain(void)
}


int
_PyTrash_begin(PyThreadState *tstate, PyObject *op)
{
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(op);
return 1;
}
++tstate->trash_delete_nesting;
return 0;
}


void
_PyTrash_end(PyThreadState *tstate)
{
--tstate->trash_delete_nesting;
if (tstate->trash_delete_later && tstate->trash_delete_nesting <= 0) {
_PyTrash_thread_destroy_chain();
}
}


void _Py_NO_RETURN
_PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg,
const char *file, int line, const char *function)
Expand Down