diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2012-09-05 22:59:49 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2012-09-05 22:59:49 (GMT) |
commit | 56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc (patch) | |
tree | ed5ce8c8953b5f8f6ed136a94629f631083f2594 /Include | |
parent | 1d857453b7065dafdc34a72c1bbb2a993782b383 (diff) | |
download | cpython-56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc.zip cpython-56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc.tar.gz cpython-56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc.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.
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.
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 315766c..6120ab813 100644 --- a/Include/object.h +++ b/Include/object.h @@ -911,24 +911,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. */ 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); #ifdef __cplusplus } diff --git a/Include/pystate.h b/Include/pystate.h index b5fe1ad..060efa7 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -113,6 +113,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; |