Issue #13992: The trashcan mechanism is now thread-safe. This eliminates

sporadic crashes in multi-thread programs when several long deallocator
chains ran concurrently and involved subclasses of built-in container
types.

Because of this change, a couple extension modules compiled for 3.2.4
(those which use the trashcan mechanism, despite it being undocumented)
will not be loadable by 3.2.3 and earlier. However, extension modules
compiled for 3.2.3 and earlier will be loadable by 3.2.4.
This commit is contained in:
Antoine Pitrou 2012-09-06 00:59:49 +02:00
parent 1d857453b7
commit 56cd62c04a
7 changed files with 140 additions and 9 deletions

View file

@ -1876,6 +1876,18 @@ _PyTrash_deposit_object(PyObject *op)
_PyTrash_delete_later = op;
}
/* The equivalent API, using per-thread state recursion info */
void
_PyTrash_thread_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 *) tstate->trash_delete_later;
tstate->trash_delete_later = op;
}
/* Dealloccate all the objects in the _PyTrash_delete_later list. Called when
* the call-stack unwinds again.
*/
@ -1902,6 +1914,31 @@ _PyTrash_destroy_chain(void)
}
}
/* The equivalent API, using per-thread state recursion info */
void
_PyTrash_thread_destroy_chain(void)
{
PyThreadState *tstate = PyThreadState_GET();
while (tstate->trash_delete_later) {
PyObject *op = tstate->trash_delete_later;
destructor dealloc = Py_TYPE(op)->tp_dealloc;
tstate->trash_delete_later =
(PyObject*) _Py_AS_GC(op)->gc.gc_prev;
/* Call the deallocator directly. This used to try to
* fool Py_DECREF into calling it indirectly, but
* Py_DECREF was already called on this object, and in
* assorted non-release builds calling Py_DECREF again ends
* up distorting allocation statistics.
*/
assert(op->ob_refcnt == 0);
++tstate->trash_delete_nesting;
(*dealloc)(op);
--tstate->trash_delete_nesting;
}
}
#ifndef Py_TRACE_REFS
/* For Py_LIMITED_API, we need an out-of-line version of _Py_Dealloc.
Define this here, so we can undefine the macro. */