summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2012-09-05 23:17:42 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2012-09-05 23:17:42 (GMT)
commit5b4faae30748c09930fa053442e1d6ff2823823c (patch)
tree8372fb8975488a6cb3fb5295ef52badfb31aa93d /Include
parent11946fbe804d99d26724e65dcb061cda6666c4e9 (diff)
parent56cd62c04a7fbd9d923de000e6e6734cf8ac9ddc (diff)
downloadcpython-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.h27
-rw-r--r--Include/pystate.h3
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;