diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -973,22 +973,23 @@ with the call stack never exceeding a de PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*); PyAPI_FUNC(void) _PyTrash_destroy_chain(void); -PyAPI_DATA(int) _PyTrash_delete_nesting; -PyAPI_DATA(PyObject *) _PyTrash_delete_later; #define PyTrash_UNWIND_LEVEL 50 #define Py_TRASHCAN_SAFE_BEGIN(op) \ - if (_PyTrash_delete_nesting < PyTrash_UNWIND_LEVEL) { \ - ++_PyTrash_delete_nesting; - /* The body of the deallocator is here. */ + do { \ + PyThreadState *_tstate = PyThreadState_GET(); \ + if (_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL) { \ + ++_tstate->trash_delete_nesting; + /* The body of the deallocator is here. */ #define Py_TRASHCAN_SAFE_END(op) \ - --_PyTrash_delete_nesting; \ - if (_PyTrash_delete_later && _PyTrash_delete_nesting <= 0) \ - _PyTrash_destroy_chain(); \ - } \ - else \ - _PyTrash_deposit_object((PyObject*)op); + --_tstate->trash_delete_nesting; \ + if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \ + _PyTrash_destroy_chain(); \ + } \ + else \ + _PyTrash_deposit_object((PyObject*)op); \ + } while (0); #ifdef __cplusplus } diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -95,6 +95,9 @@ typedef struct _ts { PyObject *async_exc; /* Asynchronous exception to raise */ long thread_id; /* Thread id where this tstate was created */ + int trash_delete_nesting; + PyObject *trash_delete_later; + /* XXX signal handlers should also be here */ } PyThreadState; diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -2421,11 +2421,12 @@ PyObject *_PyTrash_delete_later = NULL; void _PyTrash_deposit_object(PyObject *op) { + PyThreadState *tstate = PyThreadState_GET(); assert(PyObject_IS_GC(op)); assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); assert(op->ob_refcnt == 0); - _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; - _PyTrash_delete_later = op; + _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *) tstate->trash_delete_later; + tstate->trash_delete_later = op; } /* Dealloccate all the objects in the _PyTrash_delete_later list. Called when @@ -2434,11 +2435,12 @@ void void _PyTrash_destroy_chain(void) { - while (_PyTrash_delete_later) { - PyObject *op = _PyTrash_delete_later; + PyThreadState *tstate = PyThreadState_GET(); + while (tstate->trash_delete_later) { + PyObject *op = tstate->trash_delete_later; destructor dealloc = Py_TYPE(op)->tp_dealloc; - _PyTrash_delete_later = + tstate->trash_delete_later = (PyObject*) _Py_AS_GC(op)->gc.gc_prev; /* Call the deallocator directly. This used to try to @@ -2448,9 +2450,9 @@ void * up distorting allocation statistics. */ assert(op->ob_refcnt == 0); - ++_PyTrash_delete_nesting; + ++tstate->trash_delete_nesting; (*dealloc)(op); - --_PyTrash_delete_nesting; + --tstate->trash_delete_nesting; } } diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -896,6 +896,7 @@ subtype_dealloc(PyObject *self) { PyTypeObject *type, *base; destructor basedealloc; + PyThreadState *tstate = PyThreadState_GET(); /* Extract the type; we expect it to be a heap type */ type = Py_TYPE(self); @@ -944,9 +945,9 @@ subtype_dealloc(PyObject *self) /* UnTrack and re-Track around the trashcan macro, alas */ /* See explanation at end of function for full disclosure */ PyObject_GC_UnTrack(self); - ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; Py_TRASHCAN_SAFE_BEGIN(self); - --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; /* DO NOT restore GC tracking at this point. weakref callbacks * (if any, and whether directly here or indirectly in something we * call) may trigger GC, and if self is tracked at that point, it @@ -1024,9 +1025,9 @@ subtype_dealloc(PyObject *self) Py_DECREF(type); endlabel: - ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; Py_TRASHCAN_SAFE_END(self); - --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; /* Explanation of the weirdness around the trashcan macros: diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -192,6 +192,9 @@ new_threadstate(PyInterpreterState *inte tstate->c_profileobj = NULL; tstate->c_traceobj = NULL; + tstate->trash_delete_nesting = 0; + tstate->trash_delete_later = NULL; + if (init) _PyThreadState_Init(tstate);