mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
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 2.7.4 (those which use the trashcan mechanism, despite it being undocumented) will not be loadable by 2.7.3 and earlier. However, extension modules compiled for 2.7.3 and earlier will be loadable by 2.7.4.
This commit is contained in:
parent
c5eec0e387
commit
58098a77e6
7 changed files with 140 additions and 9 deletions
|
@ -2428,6 +2428,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.
|
||||
*/
|
||||
|
@ -2454,6 +2466,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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue