diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2012-09-05 23:17:42 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2012-09-05 23:17:42 (GMT) |
commit | 5b4faae30748c09930fa053442e1d6ff2823823c (patch) | |
tree | 8372fb8975488a6cb3fb5295ef52badfb31aa93d /Include | |
parent | 11946fbe804d99d26724e65dcb061cda6666c4e9 (diff) | |
parent | 56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc (diff) | |
download | cpython-5b4faae30748c09930fa053442e1d6ff2823823c.zip cpython-5b4faae30748c09930fa053442e1d6ff2823823c.tar.gz cpython-5b4faae30748c09930fa053442e1d6ff2823823c.tar.bz2 |
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.
Note that the trashcan functions are part of the stable ABI, therefore
they have to be kept around for binary compatibility of extensions.
Diffstat (limited to 'Include')
-rw-r--r-- | Include/object.h | 27 | ||||
-rw-r--r-- | Include/pystate.h | 3 |
2 files changed, 21 insertions, 9 deletions
diff --git a/Include/object.h b/Include/object.h index 709a9ff..387cadb 100644 --- a/Include/object.h +++ b/Include/object.h @@ -961,24 +961,33 @@ chain of N deallocations is broken into N / PyTrash_UNWIND_LEVEL pieces, with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL. */ +/* 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_DATA(int) _PyTrash_delete_nesting; PyAPI_DATA(PyObject *) _PyTrash_delete_later; +/* The new thread-safe private API, invoked by the macros below. */ +PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*); +PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void); + #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_thread_destroy_chain(); \ + } \ + else \ + _PyTrash_thread_deposit_object((PyObject*)op); \ + } while (0); #ifndef Py_LIMITED_API PyAPI_FUNC(void) diff --git a/Include/pystate.h b/Include/pystate.h index 25c2faa..2017b02 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -114,6 +114,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; |